从MongoDB 4.2开始,您可以将聚合管道用于更新操作。 通过更新操作,聚合管道可以包括以下阶段:
使用聚合管道允许使用表达性更强的update语句,比如根据当前字段值表示条件更新,或者使用另一个字段的值更新一个字段。
例1
创建一个示例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.collection.updateOne()
操作使用聚合管道使用**_id**更新文档:3:
db.students.updateOne( { _id: 3 }, [ { $set: { "test3": 98, modified: "$$NOW"} } ] )
具体地说,管道包括$set
阶段,该阶段将test3字段(并将其值设置为98)添加到文档中,并将修改后的字段设置为当前日期时间。 对于当前日期时间,该操作将聚合变量NOW
用于(以访问变量,以**$$**为前缀并用引号引起来)。
要验证更新,您可以查询集合:
db.students.find().pretty()
例2
创建一个示例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.collection.updateMany()
操作使用聚合管道来标准化文档的字段(即,集合中的文档应具有相同的字段)并更新修改后的字段:
db.students2.updateMany( {},
[
{ $replaceRoot: { newRoot:
{ $mergeObjects: [ { quiz1: 0, quiz2: 0, test1: 0, test2: 0 }, "$$ROOT" ] }
} },
{ $set: { modified: "$$NOW"} }
]
)
具体来说,管道包括:
$set
阶段用于将修改的字段更新到当前日期时间。 对于当前日期时间,该操作将聚合变量NOW用于(以访问变量,以**$$**为前缀并用引号引起来)。
要验证更新,您可以查询集合:
例3
创建一个示例students3集合(如果该集合当前不存在,则插入操作将创建该集合):
db.students3.insert([
{ "_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.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
阶段来计算测试数组元素的截断平均值,并将修改后的字段更新为当前日期时间。 要计算截断的平均值,此阶段使用**$avg和$trunc
表达式。 对于当前日期时间,该操作将聚合变量NOW
用于(以访问变量,以$$**为前缀并用引号引起来).
例4
创建一个示例students4集合(如果该集合当前不存在,则插入操作将创建该集合):
db.students4.insertMany([
{ "_id" : 1, "quizzes" : [ 4, 6, 7 ] },
{ "_id" : 2, "quizzes" : [ 5 ] },
{ "_id" : 3, "quizzes" : [ 10, 10, 10 ] }
])
要验证,请查询集合:
以下db.collection.updateOne()
操作使用聚合管道将测验分数添加到具有**_id**的文档中:2:
db.students4.updateOne( { _id: 2 },
[ { $set: { quizzes: { $concatArrays: [ "$quizzes", [ 8, 6 ] ] } } } ]
)
要验证,请查询集合:
例5
创建一个示例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.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
表达式一起使用。
要验证更新,您可以查询集合:
其他例子
有关其他示例,另请参见各种更新方法页面:
译者:杨帅
校对:杨帅