文档菜单
文档首页
/
MongoDB 手册
/ /

使用聚合管道的更新

本页内容

  • 在 Atlas 中创建更新聚合管道
  • 访问聚合管道构建器。
  • 创建一个用于执行更新的聚合管道。
  • 导出聚合管道。
  • 示例
  • 使用 $set 的 updateOne
  • 使用 $replaceRoot 和 $set 的 updateMany
  • 使用 $set 的 updateMany
  • 使用 $set 的 updateOne
  • 使用 $addFields 的 updateMany
  • 使用 let 变量的更新
  • 其他示例

要执行更新操作,您可以使用聚合管道。您可以在 MongoDB Atlas、MongoDB Compass、MongoDB Shell 或 Drivers 中构建和执行聚合管道以执行更新。MongoDB AtlasMongoDB CompassMongoDB Shell驱动程序

更新操作中,聚合管道可以包含以下阶段:

使用聚合管道可以创建更丰富的更新语句,例如根据当前字段值表达条件更新,或者使用另一个字段(或多个字段)的值来更新一个字段。

您可以使用MongoDB Atlas UI构建聚合管道以执行更新。要在MongoDB Atlas UI中创建和执行聚合管道,您必须拥有项目数据访问只读角色或更高角色。

1
  1. 选择集合的数据库。

    左侧的面板和命名空间列出数据库中的集合。

  2. 选择集合。

    在左侧面板或主面板中选择集合。主面板显示查找索引聚合视图。

  3. 选择聚合视图。

    首次打开聚合视图时,Atlas显示一个空的聚合管道。

2
  1. 选择聚合阶段。

    从左下角的下拉菜单中选择一个聚合阶段。

    下拉菜单右侧的切换按钮决定了该阶段是否启用。

    要使用聚合执行更新,请使用以下阶段之一

  2. 填写您的聚合阶段。

    填写您的阶段,并使用适当的值。如果注释模式已启用,管道构建器将为您提供所选阶段的语法指南。

    您修改阶段时,Atlas会根据当前阶段的输出更新右侧的预览文档。

    有关在聚合阶段可能包含的示例,请参阅此页面的示例

    根据需要添加阶段。有关在Atlas中创建聚合管道的更多信息,请参阅创建聚合管道

3
  1. 点击“导出”。

    您可以在管道构建器的顶部找到此按钮。

  2. 选择您想要的导出语言。

    导出到菜单中,选择您想要的语言。

    左侧的我的管道窗格显示您的管道在MongoDB Shell语法中。您可以直接复制以在MongoDB Shell.

    右侧的窗格显示所选语言的管道。选择您喜欢的语言。

  3. 如有需要,请选择选项。

    (可选):勾选包含导入语句选项,以包含所选语言的必需导入语句。

    (可选):勾选包含驱动程序语法选项,以包含用于

    • 初始化客户端的特定代码

    • 指定数据库和集合

    • 执行聚合操作

  4. 复制管道。

    点击管道右上角的复制按钮,将所选语言的管道复制到您的剪贴板。将复制的管道粘贴到您的应用程序中。

以下示例演示了如何使用聚合管道阶段 $set$replaceRoot$addFields 来执行更新。

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

创建一个示例 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"} }
]
)

具体来说,管道包括

  • 一个 $replaceRoot 阶段,使用 $mergeObjects 表达式为 quiz1quiz2test1test2 字段设置默认值。聚合变量 ROOT 指的是当前正在修改的文档。要访问变量,请使用 $$ 前缀并加引号。当前文档字段将覆盖默认值。

  • 一个 $set 阶段,将 modified 字段更新为当前日期和时间。该操作使用聚合变量 NOW 来获取当前日期和时间。要访问变量,请使用 $$ 前缀并加引号。

为了验证更新,您可以查询集合

db.students2.find()

创建一个示例 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 来表示当前日期和时间。要访问变量,请使用 $$ 作为前缀,并用引号括起来。

  • 一个 $set 阶段,用于根据 average 添加 grade 字段,使用 $switch 表达式。

为了验证更新,您可以查询集合

db.students3.find()

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

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

版本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' }
]

另请参阅各种更新方法页面以获取更多示例

返回

更新