Docs 菜单

Docs 主页开发应用程序MongoDB Manual

使用聚合管道进行更新。

在此页面上

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

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

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

使用聚合分析管道可以进行更具表现力的更新声明,例如基于当前字段值的Express条件更新或使用另一个字段的值更新一个字段。

您可以使用 MongoDB Atlas 用户界面构建聚合管道来执行更新。要在 MongoDB Atlas 用户界面中创建和执行聚合管道,您必须具有Project Data Access Read Only角色或更高级别的角色。

1
1

主面板和左侧的 Namespaces 列出了数据库中的集合。

2

从左侧或主面板中选择集合。主面板显示 Find(查找)、Indexes(索引)和 Aggregation(聚合)视图。

3

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

2
1

从左下角面板的 Select 下拉菜单中选择聚合阶段。

下拉列表菜单右侧的切换指示是否已启用该阶段。

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

2

用适当的值填充您的阶段。如果启用了评论模式,则管道构建器会为所选阶段提供语法指南。

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

有关聚合阶段可能包含的内容的示例,请参阅本页上的示例

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

3
1

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

2

Export Pipeline To 菜单中,选择所需的语言。

左侧的 My Pipeline 窗格以 MongoDB Shell 语法显示您的管道。您可以直接复制此语法以便在 MongoDB Shell 中执行您的管道。

右侧的窗格将以所选语言显示您的管道。选择您的首选语言。

3

(可选) :选中 Include Import Statements 选项,以包含选定语言所需的导入语句。

(可选):选中 Include Driver Syntax 选项以包含特定于驱动程序的代码:

  • 对客户端进行初始化

  • 指定数据库和集合

  • 执行聚合操作

4

单击管道右上方的 Copy(复制)按钮,从而将所选语言的管道复制到剪贴板。将复制的管道粘贴到您的应用程序中。

以下示例演示了如何使用聚合管道阶段 $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"} }
]
)

具体而言,管道包括:

  • 附带 $mergeObjects 表达式的 $replaceRoot 阶段,以便为 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 阶段,以便使用 $switch 表达式并根据 average 来添加 grade 字段。

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

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

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

← 更新文档