Updates with Aggregation Pipeline使用聚合管道进行更新

Starting in MongoDB 4.2, you can use the aggregation pipeline for update operations. 从MongoDB 4.2开始,您可以使用聚合管道进行更新操作。With the update operations, the aggregation pipeline can consist of the following stages:通过更新操作,聚合管道可以由以下阶段组成:

$addFields $set
$project $unset
$replaceRoot $replaceWith

Using the aggregation pipeline allows for a more expressive update statement, such as expressing conditional updates based on current field values or updating one field using the value of another field(s).使用聚合管道允许更具表现力的update语句,例如基于当前字段值表示条件更新,或者使用另一个字段的值更新一个字段。

Example 1例1

You can try out the example in the provided shell. 您可以在提供的shell中尝试该示例。Click inside the shell to connect. 在外壳内部单击以进行连接。Once connected, you can run the examples in the shell.连接后,可以在shell中运行示例。

Create an example students collection (if the collection does not currently exist, insert operations will create the collection):创建示例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") }
])

To verify, query the collection:要验证,请查询集合:

db.students.find()

The following db.collection.updateOne() operation uses an aggregation pipeline to update the document with _id: 3:以下db.collection.updateOne()操作使用聚合管道更新_id3的文档:

db.students.updateOne( { _id: 3 }, [ { $set: { "test3": 98, modified: "$$NOW"} } ] )

Specifically, the pipeline consists of a $set stage which adds the test3 field (and sets its value to 98) to the document and sets the modified field to the current datetime. 具体地说,管道由$set阶段组成,它将test3字段(并将其值设置为98)添加到文档中,并将修改后的字段设置为当前日期时间。For the current datetime, the operation uses the aggregation variable NOW for the (to access the variable, prefix with $$ and enclose in quotes).对于当前日期时间,该操作将使用聚合变量NOW(要访问该变量,请使用$$前缀并用引号括起来)。

To verify the update, you can query the collection:要验证更新,可以查询集合:

db.students.find().pretty()

Example 2例2

You can try out the examples in the provided shell. 您可以在提供的shell中尝试这些示例。Click inside the shell to connect. Once connected, you can run the examples in the shell.在外壳内部单击以进行连接。连接后,可以在shell中运行示例。

Create an example students2 collection (if the collection does not currently exist, insert operations will create the collection):创建示例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") },
])

To verify, query the collection:要验证,请查询集合:

db.students2.find()

The following db.collection.updateMany() operation uses an aggregation pipeline to standardize the fields for the documents (i.e. documents in the collection should have the same fields) and update the modified field:以下db.collection.updateMany()操作使用聚合管道来标准化文档的字段(即集合中的文档应具有相同的字段)并更新modified字段:

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

Specifically, the pipeline consists of:具体而言,管道包括:

  • a $replaceRoot stage with an $mergeObjects expression to set default values for the quiz1, quiz2, test1 and test2 fields. 带有$mergeObjects表达式的$replaceRoot阶段,用于设置quiz1quiz2test1test2字段的默认值。The aggregation variable ROOT refers to the current document being modified (to access the variable, prefix with $$ and enclose in quotes). 聚合变量ROOT表示正在修改的当前文档(要访问该变量,请以$$作为前缀并用引号括起来)。The current document fields will override the default values.当前文档字段将覆盖默认值。
  • a $set stage to update the modified field to the current datetime. $set阶段,用于将modified字段更新为当前日期时间。For the current datetime, the operation uses the aggregation variable NOW for the (to access the variable, prefix with $$ and enclose in quotes).对于当前日期时间,该操作使用聚合变量NOW(要访问该变量,请使用$$前缀并用引号括起来)。

To verify the update, you can query the collection:要验证更新,可以查询集合:

db.students2.find()

Example 3例3

You can try out the examples in the provided shell. 您可以在提供的shell中尝试这些示例。Click inside the shell to connect. 在外壳内部单击以进行连接。Once connected, you can run the examples in the shell.连接后,可以在shell中运行示例。

Create an example students3 collection (if the collection does not currently exist, insert operations will create the collection):创建示例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") }
]);

To verify, query the collection:要验证,请查询集合:

db.students3.find()

The following db.collection.updateMany() operation uses an aggregation pipeline to update the documents with the calculated grade average and letter grade.下面的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"
     } } } }
   ]
)

Specifically, the pipeline consists of:具体而言,管道包括:

  • a $set stage to calculate the truncated average value of the tests array elements and to update the modified field to the current datetime. $set阶段,用于计算test数组元素的截断平均值,并将modified字段更新为当前日期时间。To calculate the truncated average, the stage uses the $avg and $trunc expressions. 为了计算截断的平均值,阶段使用$avg$trunc表达式。For the current datetime, the operation uses the aggregation variable NOW for the (to access the variable, prefix with $$ and enclose in quotes)对于当前日期时间,该操作将使用聚合变量NOW(要访问该变量,请使用$$前缀并用引号括起来)
  • a $set stage to add the grade field based on the average using the $switch expression.$set阶段,用于使用$switch表达式基于average添加grade字段。

To verify the update, you can query the collection:要验证更新,可以查询集合:

db.students3.find()

Example 4例4

You can try out the examples in the provided shell. 您可以在提供的shell中尝试这些示例。Click inside the shell to connect. Once connected, you can run the examples in the shell.在外壳内部单击以进行连接。连接后,可以在shell中运行示例。

Create an example students4 collection (if the collection does not currently exist, insert operations will create the collection):创建示例students4集合(如果该集合当前不存在,则插入操作将创建该集合):

db.students4.insertMany([
  { "_id" : 1, "quizzes" : [ 4, 6, 7 ] },
  { "_id" : 2, "quizzes" : [ 5 ] },
  { "_id" : 3, "quizzes" : [ 10, 10, 10 ] }
])

To verify, query the collection:要验证,请查询集合:

db.students4.find()

The following db.collection.updateOne() operation uses an aggregation pipeline to add quiz scores to the document with _id: 2:以下db.collection.updateOne()操作使用聚合管道将测验分数添加到_id: 2的文档中:

db.students4.updateOne( { _id: 2 },
  [ { $set: { quizzes: { $concatArrays: [ "$quizzes", [ 8, 6 ]  ] } } } ]
)

To verify the update, query the collection:要验证更新,请查询集合:

db.students4.find()

Example 5例5

You can try out the examples in the provided shell. 您可以在提供的shell中尝试这些示例。Click inside the shell to connect. Once connected, you can run the examples in the shell.在外壳内部单击以进行连接。连接后,可以在shell中运行示例。

Create an example temperatures collection that contains temperatures in Celsius (if the collection does not currently exist, insert operations will create the collection):创建包含摄氏温度的示例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 ] }
])

To verify, query the collection:要验证,请查询集合:

db.temperatures.find()

The following db.collection.updateMany() operation uses an aggregation pipeline to update the documents with the corresponding temperatures in Fahrenheit:以下db.collection.updateMany()操作使用聚合管道以相应的华氏温度更新文档:

db.temperatures.updateMany( { },
  [
    { $addFields: { "tempsF": {
          $map: {
             input: "$tempsC",
             as: "celsius",
             in: { $add: [ { $multiply: ["$$celsius", 9/5 ] }, 32 ] }
          }
    } } }
  ]
)

Specifically, the pipeline consists of an $addFields stage to add a new array field tempsF that contains the temperatures in Fahrenheit. 具体来说,管道包含一个$addFields阶段,用于添加一个新的数组字段tempsF,其中包含以华氏温度为单位的温度。To convert each celsius temperature in the tempsC array to Fahrenheit, the stage uses the $map expression with $add and $multiply expressions.要将tempsC数组中的每个摄氏温度转换为华氏温度,阶段使用带有$add$multiply表达式的$map表达式。

To verify the update, you can query the collection:要验证更新,可以查询集合:

db.temperatures.find()

Additional Examples其他示例

See also the various update method pages for additional examples:有关其他示例,请参阅各种更新方法页面: