聚合管道更新

从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.students.find()

以下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.students2.find()

以下db.collection.updateMany() 操作使用聚合管道来标准化文档的字段(即,集合中的文档应具有相同的字段)并更新修改后的字段:

db.students2.updateMany( {},
    [
        { $replaceRoot: { newRoot: 
            { $mergeObjects: [ { quiz1: 0, quiz2: 0, test1: 0, test2: 0 }, "$$ROOT" ] } 
    } },
        { $set: { modified: "$$NOW"}  }
    ]
)

具体来说,管道包括:

  • $replaceRoot 阶段,带有 $mergeObjects表达式,可为quiz1quiz2test1test2字段设置默认值。 聚集变量ROOT 指的是正在修改的当前文档(以访问变量,以**$$**为前缀并用引号引起来)。 当前文档字段将覆盖默认值。

  • $set 阶段用于将修改的字段更新到当前日期时间。 对于当前日期时间,该操作将聚合变量NOW用于(以访问变量,以**$$**为前缀并用引号引起来)。

要验证更新,您可以查询集合:

db.students2.find()

例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.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阶段来计算测试数组元素的截断平均值,并将修改后的字段更新为当前日期时间。 要计算截断的平均值,此阶段使用**$avg$trunc 表达式。 对于当前日期时间,该操作将聚合变量NOW 用于(以访问变量,以$$**为前缀并用引号引起来).

  • 一个$set 阶段,用于使用$switch 表达式根据平均值添加年级字段。

    要验证更新,您可以查询集合:

    db.students3.find()

例4

创建一个示例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()

例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.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()

其他例子

有关其他示例,另请参见各种更新方法页面:

译者:杨帅

校对:杨帅

最后更新于