要执行更新操作,可以使用聚合管道。您可以构建并执行聚合管道以在 MongoDB Atlas、MongoDB Compass、MongoDB Shell 或 Drivers 中执行更新。
通过更新操作,聚合管道可以包含以下阶段:
使用聚合分析管道可以进行更具表现力的更新声明,例如基于当前字段值的Express条件更新或使用另一个字段的值更新一个字段。
在 Atlas 中创建更新聚合管道
您可以使用 MongoDB Atlas 用户界面来构建聚合管道,从而执行更新。要在 MongoDB Atlas UI 中创建和执行聚合管道,您必须具有 Project Data Access Read Only 或更高级别的角色。
导出聚合管道。
单击“导出为语言”。
您可以在管道构建器顶部找到此按钮。
选择所需的导出语言。
在 Export Pipeline To 菜单中,选择所需的语言。
左侧的 My Pipeline 窗格以 MongoDB Shell 语法显示您的管道。您可以直接复制此语法以便在 MongoDB Shell 中执行您的管道。
右侧的窗格将以所选语言显示您的管道。选择您的首选语言。
如果需要,请选择选项。
(可选) :选中 Include Import Statements 选项,以包含选定语言所需的导入语句。
(可选):选中 Include Driver Syntax 选项以包含特定于驱动程序的代码:
对客户端进行初始化
指定数据库和集合
执行聚合操作
复制管道。
单击管道右上方的 Copy(复制)按钮,从而将所选语言的管道复制到剪贴板。将复制的管道粘贴到您的应用程序中。
示例
以下示例演示了如何使用聚合管道阶段 $set、$replaceRoot 和 $addFields 来执行更新。
使用 $set 的 updateOne
创建一个 students 示例集合(如果该集合当前不存在,插入操作则会创建该集合):
db.students.insertMany( [ { _id: 1, test1: 95, test2: 92, test3: 90, modified: new Date("01/05/2020") }, { _id: 2, test1: 98, test2: 100, test3: 102, modified: new Date("01/05/2020") }, { _id: 3, test1: 95, test2: 110, modified: new Date("01/04/2020") } ] )
若要验证,请查询集合:
db.students.find()
以下 db.collection.updateOne() 操作会使用某一聚合管道来更新 _id: 3 的文档:
db.students.updateOne( { _id: 3 }, [ { $set: { "test3": 98, modified: "$$NOW"} } ] )
具体来说,管道包含一个 $set 阶段,该阶段将 test3 字段(并将其值设置为 98)添加到文档中,并将 modified 字段设置为当前日期时间。该操作使用聚合变量 NOW 作为当前日期时间。要访问变量,请使用 $$ 作为前缀,并用引号括起来。
若要验证更新,您可以查询集合:
db.students.find().pretty()
使用 $replaceRoot 和 $set 的 updateMany
创建一个 students2 示例集合(如果该集合当前不存在,插入操作则会创建该集合):
db.students2.insertMany( [ { "_id" : 1, quiz1: 8, test2: 100, quiz2: 9, modified: new Date("01/05/2020") }, { "_id" : 2, quiz2: 5, test1: 80, test2: 89, modified: new Date("01/05/2020") }, ] )
若要验证,请查询集合:
db.students2.find()
以下 db.collection.updateMany() 操作会使用某一聚合管道来标准化此文档的字段(即,集合中的文档应具有相同字段)并更新 modified 字段:
db.students2.updateMany( {}, [ { $replaceRoot: { newRoot: { $mergeObjects: [ { quiz1: 0, quiz2: 0, test1: 0, test2: 0 }, "$$ROOT" ] } } }, { $set: { modified: "$$NOW"} } ] )
具体而言,管道包括:
附带
$mergeObjects表达式的$replaceRoot阶段,以便为quiz1、quiz2、test1和test2字段设置默认值。聚合变量ROOT是指当前修改的文档。要访问此变量,请将$$用作前缀,并用引号括起来。当前文档字段将覆盖这些默认值。$set阶段,以便将modified字段更新为当前日期时间。此操作会将聚合变量NOW用作当前日期时间。要访问此变量,请将$$用作前缀,并用引号括起来。
若要验证更新,您可以查询集合:
db.students2.find()
使用 $set 的 updateMany
创建一个 students3 示例集合(如果该集合当前不存在,插入操作则会创建该集合):
db.students3.insertMany( [ { "_id" : 1, "tests" : [ 95, 92, 90 ], "modified" : ISODate("2019-01-01T00:00:00Z") }, { "_id" : 2, "tests" : [ 94, 88, 90 ], "modified" : ISODate("2019-01-01T00:00:00Z") }, { "_id" : 3, "tests" : [ 70, 75, 82 ], "modified" : ISODate("2019-01-01T00:00:00Z") } ] );
若要验证,请查询集合:
db.students3.find()
以下 db.collection.updateMany() 操作使用某一聚合管道来更新具有计算得出的平均成绩和字母成绩的文档。
db.students3.updateMany( { }, [ { $set: { average : { $trunc: [ { $avg: "$tests" }, 0 ] }, modified: "$$NOW" } }, { $set: { grade: { $switch: { branches: [ { case: { $gte: [ "$average", 90 ] }, then: "A" }, { case: { $gte: [ "$average", 80 ] }, then: "B" }, { case: { $gte: [ "$average", 70 ] }, then: "C" }, { case: { $gte: [ "$average", 60 ] }, then: "D" } ], default: "F" } } } } ] )
具体而言,管道包括:
$set阶段,以便计算tests数组元素的截断后的平均值并将modified字段更新为当前日期时间。为计算截断后的平均值,此阶段会使用$avg和$trunc表达式。该操作使用聚合变量NOW作为当前日期时间。 要访问变量,请使用$$作为前缀,并用引号括起来。
若要验证更新,您可以查询集合:
db.students3.find()
使用 $set 的 updateOne
创建一个 students4 示例集合(如果该集合当前不存在,插入操作则会创建该集合):
db.students4.insertMany( [ { "_id" : 1, "quizzes" : [ 4, 6, 7 ] }, { "_id" : 2, "quizzes" : [ 5 ] }, { "_id" : 3, "quizzes" : [ 10, 10, 10 ] } ] )
若要验证,请查询集合:
db.students4.find()
以下 db.collection.updateOne() 操作使用聚合管道向具有 _id:
2 的文档添加测验分数:
db.students4.updateOne( { _id: 2 }, [ { $set: { quizzes: { $concatArrays: [ "$quizzes", [ 8, 6 ] ] } } } ] )
若要验证更新,请查询集合:
db.students4.find()
使用 $addFields 的 updateMany
创建一个包含摄氏度温度的 temperatures 示例集合(如果该集合当前不存在,插入操作将创建该集合):
db.temperatures.insertMany( [ { "_id" : 1, "date" : ISODate("2019-06-23"), "tempsC" : [ 4, 12, 17 ] }, { "_id" : 2, "date" : ISODate("2019-07-07"), "tempsC" : [ 14, 24, 11 ] }, { "_id" : 3, "date" : ISODate("2019-10-30"), "tempsC" : [ 18, 6, 8 ] } ] )
若要验证,请查询集合:
db.temperatures.find()
以下 db.collection.updateMany() 操作使用聚合管道以相应的华氏度温度更新文档:
db.temperatures.updateMany( { }, [ { $addFields: { "tempsF": { $map: { input: "$tempsC", as: "celsius", in: { $add: [ { $multiply: ["$$celsius", 9/5 ] }, 32 ] } } } } } ] )
具体来说,此管道包含 $addFields阶段,它可用于添加包含华氏温度的新数组字段 tempsF。要将 tempsC 数组中的每个摄氏温度转换为华氏温度,此阶段会使用 $map、$add 和 $multiply 表达式。
若要验证更新,您可以查询集合:
db.temperatures.find()
使用 let 变量进行更新
版本 5.0 中的新增功能。
要定义可在命令中其他位置访问的变量,请使用 let 选项。
注意
要使用变量筛选结果,您必须在 $expr 操作符中访问该变量。
创建集合 cakeFlavors:
db.cakeFlavors.insertMany( [ { _id: 1, flavor: "chocolate" }, { _id: 2, flavor: "strawberry" }, { _id: 3, flavor: "cherry" } ] )
以下 updateOne 命令使用通过 let 选项设置的变量:
targetFlavor变量设置为cherry。此变量在$eq表达式中用于指定匹配过滤器。newFlavor变量设置为orange。此变量在$set操作符中用于指定匹配文档的更新后flavor值。
db.cakeFlavors.updateOne( { $expr: { $eq: [ "$flavor", "$$targetFlavor" ] } }, [ { $set: { flavor: "$$newFlavor" } } ], { let: { targetFlavor: "cherry", newFlavor: "orange" } } )
运行前面的更新操作后,cakeFlavors 集合将包含以下文档:
[ { _id: 1, flavor: 'chocolate' }, { _id: 2, flavor: 'strawberry' }, { _id: 3, flavor: 'orange' } ]
其他示例
另请参阅各种更新方法页面以获取其他示例: