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

更新

本页内容

  • 定义
  • 兼容性
  • 语法
  • 命令字段
  • 访问控制
  • 行为
  • 示例
  • 输出
update

update 命令用于修改集合中的文档。一个 update 命令可以包含多个更新语句。

提示

mongosh 中,此命令还可以通过以下方法运行:updateOne()updateMany()replaceOne()findOneAndReplace()findOneAndUpdate() 辅助方法.

辅助方法对 mongosh 用户来说很方便,但它们可能不会返回与数据库命令相同级别的信息。在不需要方便性或需要额外返回字段的情况下,请使用数据库命令。

此命令在以下环境中的部署中可用

  • MongoDB Atlas:云中MongoDB部署的全托管服务

注意

此命令在所有MongoDB Atlas集群中受支持。有关Atlas对所有命令的支持信息,请参阅不受支持的命令。

变更在版本5.0.

该命令有以下语法

db.runCommand(
{
update: <collection>,
updates: [
{
q: <query>,
u: <document or pipeline>,
c: <document>, // Added in MongoDB 5.0
upsert: <boolean>,
multi: <boolean>,
collation: <document>,
arrayFilters: <array>,
hint: <document|string>
},
...
],
ordered: <boolean>,
maxTimeMS: <integer>,
writeConcern: { <write concern> },
bypassDocumentValidation: <boolean>,
comment: <any>,
let: <document> // Added in MongoDB 5.0
}
)

该命令包含以下字段

字段
类型
描述
更新
string
目标集合的名称。
updates
array
对指定集合执行的一个或多个更新语句的数组。有关更新语句的详细信息,请参阅更新语句。
有序
布尔值
可选。如果true,则当更新语句失败时,不执行剩余的更新语句。如果false,则当更新失败时,继续执行剩余的更新语句(如果有的话)。默认为true
maxTimeMS
非负整数

可选。

指定毫秒的时间限制。如果您未指定maxTimeMS的值,则操作不会超时。值为0明确指定默认的无界行为。

MongoDB使用与db.killOp()相同的机制终止超出分配时间限制的操作。MongoDB仅在指定的中断点之一终止操作。

writeConcern
文档

可选。一个文档,表示update命令的写入关注点。省略以使用默认写入关注点。

如果在事务中运行操作,请不要显式设置操作的写入关注点。有关在事务中使用写入关注点的信息,请参阅事务和写入关注点。

bypassDocumentValidation
布尔值
可选。启用update在操作期间绕过文档验证。这允许您更新不满足验证要求的文档。
comment
任何

可选。附加到此命令的用户提供的注释。一旦设置,此注释将在以下位置显示与该命令相关的记录:

注释可以是任何有效的BSON类型(字符串、整数、对象、数组等)。

文档

可选。

指定包含变量列表的文档。这允许您通过将变量与查询文本分离来提高命令的可读性。

文档语法是

{
<variable_name_1>: <expression_1>,
...,
<variable_name_n>: <expression_n>
}

变量设置为表达式返回的值,之后无法更改。

要在命令中访问变量的值,请使用双美元符号前缀($$)以及变量名,形式为$$<variable_name>。例如:$$targetTotal

完整示例,请参阅 let 选项或 c 字段中使用变量。

在版本5.0.

updates 数组的每个元素都是一个更新语句文档。每个文档包含以下字段

字段
类型
描述
文档

匹配要更新的文档的查询。使用与 查询选择器 相同的选择器,如 find() 方法中使用的。

文档或管道

要应用的修改。值可以是以下之一

有关详细信息,请参阅 行为。

文档

可选。只有当 u 是管道时,才能指定 c

指定包含变量列表的文档。这允许您通过将变量与查询文本分离来提高命令的可读性。

文档语法是

{
<variable_name_1>: <expression_1>,
...,
<variable_name_n>: <expression_n>
}

变量设置为表达式返回的值,之后无法更改。

要在命令中访问变量的值,请使用双美元符号前缀($$)以及变量名,形式为$$<variable_name>。例如:$$targetTotal

要使用变量来过滤结果,必须在 $expr 操作符中访问该变量。

有关使用 let 和变量的完整示例,请参阅 let 选项或 c 字段中使用变量。

在版本5.0.

布尔值

可选。当 true 时,update

  • 如果没有文档匹配 query,则创建一个新的文档。有关更多详细信息,请参阅 upsert 行为。

  • 更新匹配 query 的单个文档。

如果同时设置了 upsertmulti,且查询没有匹配到文档,则更新操作只插入单个文档。

为了避免多次 更新,请确保 查询 字段具有 唯一索引。请参见 具有唯一索引的更新 中的示例。

默认为 false,当没有匹配项时不会插入新文档。

multi
布尔值

可选。如果设置为 true,则更新满足查询条件的所有文档。如果设置为 false,则更新仅限于满足查询条件的一个文档。默认为 false

在更新多个文档时,如果单个文档更新失败,则不会更新后续的文档。请参见 多更新失败 了解此行为的更多详细信息。

collation
文档

可选。

指定操作中使用的 校对规则

校对规则 允许用户指定特定于语言的字符串比较规则,例如字母大小写和重音符号的规则。

校对选项的语法如下

collation: {
locale: <string>,
caseLevel: <boolean>,
caseFirst: <string>,
strength: <int>,
numericOrdering: <boolean>,
alternate: <string>,
maxVariable: <string>,
backwards: <boolean>
}

指定校对规则时,locale 字段是必需的;所有其他校对字段是可选的。有关字段的说明,请参阅 校对文档

如果未指定校对规则,但集合具有默认校对规则(请参阅 db.createCollection()),则操作使用集合指定的校对规则。

如果集合或操作未指定校对规则,MongoDB 使用之前版本中用于字符串比较的简单二进制比较。

您不能为操作指定多个校对规则。例如,您不能为每个字段指定不同的校对规则,或者如果在排序时执行查找,则不能为查找和排序使用不同的校对规则。

arrayFilters
array

可选。一个过滤器文档数组,用于确定要修改数组字段的更新操作中哪些数组元素。

在更新文档中,使用 $[<identifier>] 位置过滤器运算符来定义标识符,然后您在数组过滤器文档中引用该标识符。如果标识符未包含在更新文档中,则不能为该标识符有数组过滤器文档。

<identifier> 必须以小写字母开头,并且只能包含字母数字字符。

在更新文档中,您可以多次包含相同的标识符;然而,对于更新文档中每个不同的标识符($[标识符]),您必须指定一个对应的数组过滤器文档。也就是说,您不能为同一个标识符指定多个数组过滤器文档。例如,如果更新语句包含标识符 x(可能多次),您不能为包含 2 个独立过滤器文档的 arrayFilters 指定以下内容。

// INVALID
[
{ "x.a": { $gt: 85 } },
{ "x.b": { $gt: 80 } }
]

但是,您可以在单个过滤器文档中对同一标识符指定复合条件,如下面的示例所示。

// Example 1
[
{ $or: [{"x.a": {$gt: 85}}, {"x.b": {$gt: 80}}] }
]
// Example 2
[
{ $and: [{"x.a": {$gt: 85}}, {"x.b": {$gt: 80}}] }
]
// Example 3
[
{ "x.a": { $gt: 85 }, "x.b": { $gt: 80 } }
]

有关示例,请参阅为 Array Update 操作指定 arrayFilters

文档或字符串

可选。一个文档或字符串,用于指定用于支持索引以支持查询谓词。

该选项可以接受索引规范文档或索引名称字符串。

如果您指定了一个不存在的索引,则操作将出错。

有关示例,请参阅为 Update 操作指定 hint

该命令返回一个包含操作状态的文档。例如

{
"ok" : 1,
"nModified" : 0,
"n" : 1,
"upserted" : [
{
"index" : 0,
"_id" : ObjectId("52ccb2118908ccd753d65882")
}
]
}

有关输出字段的详细信息,请参阅输出。

在运行着 authorization 的部署上,用户必须拥有以下权限的访问权限

  • update 操作在指定的集合(们)上。

  • find 操作在指定的集合(们)上。

  • insert 操作在指定的集合(们)上。

内置角色 readWrite 提供了所需的权限。

更新语句字段 u 可以接受只包含 更新操作符 表达式的文档。例如

updates: [
{
q: <query>,
u: { $set: { status: "D" }, $inc: { quantity: 2 } },
...
},
...
]

然后,update 命令只更新文档中的相应字段。

更新语句字段 u 字段可以接受替换文档,即文档只包含 field:value 表达式。例如

updates: [
{
q: <query>,
u: { status: "D", quantity: 4 },
...
},
...
]

然后,update 命令会替换匹配的文档为更新文档。update 命令只能替换一个单个匹配文档;也就是说,multi字段不能设置为trueupdate 命令不会替换_id值。

如果在更新命令中将multi参数设置为true,单个文档更新失败,则该命令将不会更新其他文档。

例如,创建一个包含以下文档的members集合

db.members.insertMany( [
{ "_id" : 1, "member" : "Taylor", "status" : "pending", "points" : 1},
{ "_id" : 2, "member" : "Alexis", "status" : "enrolled", "points" : 59},
{ "_id" : 3, "member" : "Elizabeth", "status" : "enrolled", "points" : 34}
] )

以下操作在members集合上创建了一个文档验证器,规则是points值不能等于60

db.runCommand( {
collMod: "members",
validator: { points: { $ne: 60 } }
} )

此更新命令将每个文档的points字段增加1

db.runCommand(
{
update: "members",
updates: [
{
q: {},
u: { $inc: { points: 1 } },
multi: true
}
]
}
)

运行命令后,集合包含以下文档

{ _id: 1, member: 'Taylor', status: 'A', points: 2 }
{ _id: 2, member: 'Alexis', status: 'D', points: 59 }
{ _id: 3, member: 'Elizabeth', status: 'C', points: 34 }

更新命令更新了第一个文档的points值,但未能更新第二个文档,因为验证器规则规定points值不能等于60。第三个文档未更新,因为没有其他文档在写入错误后更新。

注意

如果匹配的文档子集被更新,例如,当更新会导致某些文档失败模式验证时,update 命令返回的nModified值可能不准确。

更新语句字段 u 字段可以接受一个 聚合管道 [ <阶段1>, <阶段2>, ... ],该管道指定要执行修改。管道可以由以下阶段组成

使用聚合管道可以实现更丰富的更新语句,例如根据当前字段值表达条件更新或使用其他字段(的值)更新一个字段。

例如

updates: [
{
q: <query>,
u: [
{ $set: { status: "Modified", comments: [ "$misc1", "$misc2" ] } },
{ $unset: [ "misc1", "misc2" ] }
],
...
},
...
]

注意

在管道中使用的 $set$unset 分别指的是聚合阶段 $set$unset,而不是更新操作符 $set$unset

有关示例,请参阅 使用聚合管道更新。

除非存在防止重复的唯一索引,否则 Upsert 可能会创建重复的文档。

考虑以下示例,没有名为 Andy 的文档,并且多个客户端几乎同时发出以下命令

db.runCommand(
{
update: "people",
updates: [
{ q: { name: "Andy" }, u: { $inc: { score: 1 } }, multi: true, upsert: true }
]
}
)

如果所有 update 操作在成功插入数据之前完成查询阶段,并且 name 字段上没有唯一索引,则每个 update 操作可能会导致插入,创建多个具有 name: Andy 的文档。

name 字段上创建唯一索引可以确保只创建一个文档。在有唯一索引的情况下,现在的多个 update 操作将表现出以下行为

  • 只有一个 update 操作将成功插入一个新文档。

  • 其他 update 操作将更新新插入的文档或因唯一键冲突而失败。

    为了使其他 update 操作能够更新新插入的文档,必须满足以下所有条件

    • 目标集合有一个会导致重复键错误的唯一索引。

    • 更新操作不是 updateManymulti 被设置为 false

    • 更新匹配条件可以是以下之一

      • 一个单独的等价谓词。例如 { "fieldA" : "valueA" }

      • 等价谓词的逻辑与。例如 { "fieldA" : "valueA", "fieldB" : "valueB" }

    • 等价谓词中的字段与唯一索引键模式中的字段匹配。

    • 更新操作不会修改唯一索引键模式中的任何字段。

以下表格显示了在键冲突发生时,upsert 操作的示例,这些操作要么导致更新,要么失败。

唯一索引键模式
更新操作
结果
{ name : 1 }
db.people.updateOne(
{ name: "Andy" },
{ $inc: { score: 1 } },
{ upsert: true }
)
匹配文档的 score 字段增加1。
{ name : 1 }
db.people.updateOne(
{ name: { $ne: "Joe" } },
{ $set: { name: "Andy" } },
{ upsert: true }
)
操作失败,因为它修改了唯一索引键模式中的字段(name)。
{ name : 1 }
db.people.updateOne(
{ name: "Andy", email: "andy@xyz.com" },
{ $set: { active: false } },
{ upsert: true }
)
操作失败,因为等价谓词字段(nameemail)与索引键字段(name)不匹配。

对于 updates 数组中的每个更新元素,查询和更新的大小之和(即 qu)必须小于或等于最大BSON文档大小

updates 数组中更新语句的总数必须小于或等于最大批量大小

命令 update 添加了对 bypassDocumentValidation 选项的支持,该选项允许您在向具有验证规则的集合插入或更新文档时跳过 文档验证

要在分片集合上使用 updatemulti: false

  • 如果您没有指定 upsert: true,则过滤器 q 必须包含对 _id 字段的等式匹配或针对单个分片(例如,通过包含分片键)。

  • 如果您指定了 upsert: true,则过滤器 q 必须包含对分片键的等式匹配。

    然而,分片集合中的文档可能会缺少 分片键字段。要定位缺少分片键的文档,您可以使用 null 等式匹配另一个过滤器条件(例如,对 _id 字段的匹配)结合使用。例如

    { _id: <value>, <shardkeyfield>: null } // _id of the document missing shard key

在替换文档时,update 首先尝试使用查询过滤器定位一个分片,如果无法通过查询过滤器定位单个分片,则尝试通过替换文档进行定位。

除非分片键字段是不可变的 _id 字段,否则您可以更新文档的分片键值。

要使用 update:

  • 您必须在 mongos 上运行。不要直接在分片上执行操作。

  • 您必须在 事务 中运行或作为 重试写入。

  • 您必须指定 multi: false

  • 您必须在完整的分片键上包含一个等价 查询过滤器

提示

由于缺失的键值作为空等价匹配的一部分返回,为避免更新空值的键,请根据需要包含额外的查询条件(例如在 _id 字段上)。

另请参阅 upsert 在分片集合上的用法。

分片集合中的文档可能缺少分片键字段。要使用 update 设置文档的 缺失 分片键,您必须在 mongos 上运行。不要在分片上直接执行此操作。

此外,以下要求也适用

任务
要求
设置为 null
  • 可以指定 multi: true

  • 如果指定了 upsert: true,则需要针对完整分片键进行等值过滤器。

设置为非-null
  • 必须 在事务内部或作为 重试写入。 执行。

  • 必须 指定 multi: false

  • 如果指定了以下任一项,则需要针对完整分片键进行等值过滤器:

    • upsert: true,或

    • 如果使用替换文档,并且新的分片键值属于不同的分片。

提示

由于缺失的键值作为空等价匹配的一部分返回,为避免更新空值的键,请根据需要包含额外的查询条件(例如在 _id 字段上)。

另请参阅

update 可用于 分布式事务 内部。

重要

在大多数情况下,分布式事务相对于单文档写入会带来更高的性能成本,因此分布式事务的可用性不应替代有效的模式设计。对于许多场景,非规范化数据模型(嵌入文档和数组)将始终是最适合您的数据和用例。也就是说,对于许多场景,适当地建模您的数据可以最大限度地减少对分布式事务的需求。

关于事务使用的其他考虑因素(例如运行时限制和oplog大小限制),请参阅生产注意事项。

如果事务不是跨分片写事务,则可以在分布式事务内部创建集合和索引。

update命令使用upsert: true可以在现有集合或不存在集合上运行。如果在不存在的集合上运行,该操作将创建该集合。

提示

另请参阅

如果在事务中运行操作,请不要显式设置操作的写入关注点。有关在事务中使用写入关注点的信息,请参阅事务和写入关注点。

使用 更新运算符 仅更新文档的指定字段。

例如,创建一个包含以下文档的members集合

db.members.insertMany([
{ _id: 1, member: "abc123", status: "Pending", points: 0, misc1: "note to self: confirm status", misc2: "Need to activate" },
{ _id: 2, member: "xyz123", status: "D", points: 59, misc1: "reminder: ping me at 100pts", misc2: "Some random comment" },
])

以下命令使用 $set$inc 更新运算符来更新 statuspoints 字段,其中 member 等于 "abc123" 的文档。

db.runCommand(
{
update: "members",
updates: [
{
q: { member: "abc123" }, u: { $set: { status: "A" }, $inc: { points: 1 } }
}
],
ordered: false,
writeConcern: { w: "majority", wtimeout: 5000 }
}
)

由于 <update> 文档没有指定可选的 multi 字段,因此即使有多个文档匹配 q 匹配条件,更新也只修改一个文档。

返回的文档显示,命令找到了并更新了一个文档。该命令返回

{ "n" : 1, "nModified" : 1, "ok" : 1, <additional fields if run on a replica set/sharded cluster> }

输出 以获取详细信息。

命令之后,集合包含以下文档

{ "_id" : 1, "member" : "abc123", "status" : "A", "points" : 1, "misc1" : "note to self: confirm status", "misc2" : "Need to activate" }
{ "_id" : 2, "member" : "xyz123", "status" : "D", "points" : 59, "misc1" : "reminder: ping me at 100pts", "misc2" : "Some random comment" }

使用更新运算符来更新文档中指定的字段,并在更新语句中将multi字段设置为true

例如,一个members集合包含以下文档

{ "_id" : 1, "member" : "abc123", "status" : "A", "points" : 1, "misc1" : "note to self: confirm status", "misc2" : "Need to activate" }
{ "_id" : 2, "member" : "xyz123", "status" : "D", "points" : 59, "misc1" : "reminder: ping me at 100pts", "misc2" : "Some random comment" }

以下命令使用$set$inc更新运算符分别修改集合中所有文档的statuspoints字段。

db.runCommand(
{
update: "members",
updates: [
{ q: { }, u: { $set: { status: "A" }, $inc: { points: 1 } }, multi: true }
],
ordered: false,
writeConcern: { w: "majority", wtimeout: 5000 }
}
)

该更新修改了与在q字段中指定的查询匹配的所有文档,即匹配集合中所有文档的空查询。

返回的文档显示命令找到了并更新了多个文档。对于副本集,命令返回

{ "n" : 2, "nModified" : 2, "ok" : 1, <additional fields if run on a replica set/sharded cluster> }

输出 以获取详细信息。

命令之后,集合包含以下文档

{ "_id" : 1, "member" : "abc123", "status" : "A", "points" : 2, "misc1" : "note to self: confirm status", "misc2" : "Need to activate" }
{ "_id" : 2, "member" : "xyz123", "status" : "A", "points" : 60, "misc1" : "reminder: ping me at 100pts", "misc2" : "Some random comment" }

update命令可以使用聚合管道进行更新。该管道可以包含以下阶段

使用聚合管道可以实现更丰富的更新语句,例如根据当前字段值表达条件更新或使用其他字段(的值)更新一个字段。

以下示例使用聚合管道使用文档中其他字段的值来修改一个字段。

一个名为 members 的集合包含以下文档

{ "_id" : 1, "member" : "abc123", "status" : "A", "points" : 2, "misc1" : "note to self: confirm status", "misc2" : "Need to activate" }
{ "_id" : 2, "member" : "xyz123", "status" : "A", "points" : 60, "misc1" : "reminder: ping me at 100pts", "misc2" : "Some random comment" }

假设不是单独的 misc1misc2 字段,而是将这些字段汇集到一个新的 comments 字段中。以下更新操作使用聚合管道添加新的 comments 字段,并从集合中的所有文档中删除 misc1misc2 字段。

  • 首先,将 status 字段设置为 "Modified",并添加一个新的字段 comments,该字段包含两个其他字段 misc1misc2 的当前内容。

  • 其次,删除 misc1misc2 字段。

db.runCommand(
{
update: "members",
updates: [
{
q: { },
u: [
{ $set: { status: "Modified", comments: [ "$misc1", "$misc2" ] } },
{ $unset: [ "misc1", "misc2" ] }
],
multi: true
}
],
ordered: false,
writeConcern: { w: "majority", wtimeout: 5000 }
}
)

注意

在管道中使用的 $set$unset 分别指的是聚合阶段 $set$unset,而不是更新操作符 $set$unset

返回的文档显示,该命令找到了并更新了多个文档。该命令返回

{ "n" : 2, "nModified" : 2, "ok" : 1, <additional fields if run on a replica set/sharded cluster> }

输出 以获取详细信息。

命令之后,集合包含以下文档

{ "_id" : 1, "member" : "abc123", "status" : "Modified", "points" : 2, "comments" : [ "note to self: confirm status", "Need to activate" ] }
{ "_id" : 2, "member" : "xyz123", "status" : "Modified", "points" : 60, "comments" : [ "reminder: ping me at 100pts", "Some random comment" ] }

聚合管道允许基于当前字段值执行条件更新,以及使用当前字段值来计算单独的字段值。

db.students.insertMany( [
{ "_id" : 1, "tests" : [ 95, 92, 90 ] },
{ "_id" : 2, "tests" : [ 94, 88, 90 ] },
{ "_id" : 3, "tests" : [ 70, 75, 82 ] }
] );

使用聚合管道,您可以更新文档,包含计算出的平均成绩和成绩等级。

db.runCommand(
{
update: "students",
updates: [
{
q: { },
u: [
{ $set: { average : { $avg: "$tests" } } },
{ $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"
} } } }
],
multi: true
}
],
ordered: false,
writeConcern: { w: "majority", wtimeout: 5000 }
}
)

注意

在管道中使用的 $set 指的是聚合阶段 $set,而不是更新运算符 $set

第一阶段
《$set》阶段根据tests字段的平均值计算一个新的字段average。有关$avg聚合运算符的更多信息,请参阅$avg
第二阶段
《$set》阶段根据上一阶段计算的average字段计算一个新的字段grade。有关$switch聚合运算符的更多信息,请参阅$switch

返回的文档显示,该命令找到了并更新了多个文档。该命令返回

{ "n" : 3, "nModified" : 3, "ok" : 1, <additional fields if run on a replica set/sharded cluster> }

命令之后,集合包含以下文档

{ "_id" : 1, "tests" : [ 95, 92, 90 ], "average" : 92.33333333333333, "grade" : "A" }
{ "_id" : 2, "tests" : [ 94, 88, 90 ], "average" : 90.66666666666667, "grade" : "A" }
{ "_id" : 3, "tests" : [ 70, 75, 82 ], "average" : 75.66666666666667, "grade" : "C" }

以下示例在members集合上执行多个更新操作

db.runCommand(
{
update: "members",
updates: [
{ q: { status: "P" }, u: { $set: { status: "D" } }, multi: true },
{ q: { _id: 5 }, u: { _id: 5, name: "abc123", status: "A" }, upsert: true }
],
ordered: false,
writeConcern: { w: "majority", wtimeout: 5000 }
}
)

返回的文档显示该命令修改了10个文档并插入了一个具有_id值为5的文档。有关详细信息,请参阅输出

{
"ok" : 1,
"nModified" : 10,
"n" : 11,
"upserted" : [
{
"index" : 1,
"_id" : 5
}
]
}

校对规则 允许用户指定特定于语言的字符串比较规则,例如字母大小写和重音符号的规则。

集合myColl有以下文档

{ _id: 1, category: "café", status: "A" }
{ _id: 2, category: "cafe", status: "a" }
{ _id: 3, category: "cafE", status: "a" }

以下操作包含排序规则选项

db.runCommand({
update: "myColl",
updates: [
{ q: { category: "cafe", status: "a" }, u: { $set: { status: "Updated" } }, collation: { locale: "fr", strength: 1 } }
]
})

当更新数组字段时,您可以指定 arrayFilters 来确定要更新的数组元素。

创建一个包含以下文档的集合 students

db.students.insertMany( [
{ "_id" : 1, "grades" : [ 95, 92, 90 ] },
{ "_id" : 2, "grades" : [ 98, 100, 102 ] },
{ "_id" : 3, "grades" : [ 95, 110, 100 ] }
] );

为了修改 grades 数组中所有大于或等于 100 的元素,使用带有 arrayFilters 选项的过滤位置操作符 $[<identifier>]

db.runCommand( {
update: "students",
updates: [
{ q: { grades: { $gte: 100 } }, u: { $set: { "grades.$[element]" : 100 } }, arrayFilters: [ { "element": { $gte: 100 } } ], multi: true}
]
} )

操作完成后,集合包含以下文档

{ "_id" : 1, "grades" : [ 95, 92, 90 ] }
{ "_id" : 2, "grades" : [ 98, 100, 100 ] }
{ "_id" : 3, "grades" : [ 95, 100, 100 ] }

创建一个包含以下文档的集合 students2

db.students2.insertMany( [
{
"_id" : 1,
"grades" : [
{ "grade" : 80, "mean" : 75, "std" : 6 },
{ "grade" : 85, "mean" : 90, "std" : 4 },
{ "grade" : 85, "mean" : 85, "std" : 6 }
]
},
{
"_id" : 2,
"grades" : [
{ "grade" : 90, "mean" : 75, "std" : 6 },
{ "grade" : 87, "mean" : 90, "std" : 3 },
{ "grade" : 85, "mean" : 85, "std" : 4 }
]
}
] )

要修改grades数组中所有成绩大于或等于85的元素的mean字段的值,请使用带有arrayFilters的筛选位置操作符$[<identifier>]

db.runCommand({
update: "students2",
updates: [
{ q: { }, u: { $set: { "grades.$[elem].mean" : 100 } }, arrayFilters: [ { "elem.grade": { $gte: 85 } } ], multi: true }
]
})

操作后,集合具有以下文档

{
"_id" : 1,
"grades" : [
{ "grade" : 80, "mean" : 75, "std" : 6 },
{ "grade" : 85, "mean" : 100, "std" : 4 },
{ "grade" : 85, "mean" : 100, "std" : 6 }
]
}
{
"_id" : 2,
"grades" : [
{ "grade" : 90, "mean" : 100, "std" : 6 },
{ "grade" : 87, "mean" : 100, "std" : 3 },
{ "grade" : 85, "mean" : 100, "std" : 4 }
]
}

创建以下文档的members集合

db.members.insertMany([
{ "_id" : 1, "member" : "abc123", "status" : "P", "points" : 0, "misc1" : null, "misc2" : null },
{ "_id" : 2, "member" : "xyz123", "status" : "A", "points" : 60, "misc1" : "reminder: ping me at 100pts", "misc2" : "Some random comment" },
{ "_id" : 3, "member" : "lmn123", "status" : "P", "points" : 0, "misc1" : null, "misc2" : null },
{ "_id" : 4, "member" : "pqr123", "status" : "D", "points" : 20, "misc1" : "Deactivated", "misc2" : null },
{ "_id" : 5, "member" : "ijk123", "status" : "P", "points" : 0, "misc1" : null, "misc2" : null },
{ "_id" : 6, "member" : "cde123", "status" : "A", "points" : 86, "misc1" : "reminder: ping me at 100pts", "misc2" : "Some random comment" }
])

在集合上创建以下索引

db.members.createIndex( { status: 1 } )
db.members.createIndex( { points: 1 } )

以下更新操作明确提示使用索引{ status: 1 }

注意

如果您指定了一个不存在的索引,则操作将出错。

db.runCommand({
update: "members",
updates: [
{ q: { "points": { $lte: 20 }, "status": "P" }, u: { $set: { "misc1": "Need to activate" } }, hint: { status: 1 }, multi: true }
]
})

更新命令返回以下结果

{ "n" : 3, "nModified" : 3, "ok" : 1 }

要查看使用的索引,在操作上运行explain

db.runCommand(
{
explain: {
update: "members",
updates: [
{ q: { "points": { $lte: 20 }, "status": "P" }, u: { $set: { "misc1": "Need to activate" } }, hint: { status: 1 }, multi: true }
]
},
verbosity: "queryPlanner"
}
)

explain不会修改文档。

在版本5.0.

变量可以在let选项或c字段中定义,并在updates数组中访问。

注意

要使用变量进行结果筛选,必须在$expr操作符内访问该变量。

创建集合cakeFlavors

db.cakeFlavors.insertMany( [
{ _id: 1, flavor: "chocolate" },
{ _id: 2, flavor: "strawberry" },
{ _id: 3, flavor: "cherry" }
] )

以下示例在let中定义了targetFlavornewFlavor变量,并使用这些变量将蛋糕口味从樱桃改为橙子。

db.runCommand( {
update: db.cakeFlavors.getName(),
updates: [
{ q: { $expr: { $eq: [ "$flavor", "$$targetFlavor" ] } },
u: [ { $set: { flavor: "$$newFlavor" } } ] }
],
let : { targetFlavor: "cherry", newFlavor: "orange" }
} )

下一个示例在c中定义了targetFlavornewFlavor变量,并使用这些变量将蛋糕口味从巧克力改为香草。

db.runCommand( {
update: db.cakeFlavors.getName(),
updates: [
{ q: { $expr: { $eq: [ "$flavor", "$$targetFlavor" ] } },
u: [ { $set: { flavor: "$$newFlavor" } } ],
c: { targetFlavor: "chocolate", newFlavor: "vanilla" } }
]
} )

返回的文档包含以下字段的子集

update.ok

命令的状态。

update.n

update命令接受一个文档更新数组,其中一些可以是upserts。对于更新,n是选择用于更新的文档数。对于upsert,n是插入的文档的1。服务器将所有更新和upserts的n值相加,并将总和作为update.n返回。

如果更新操作没有改变文档,例如,使用$set表达式更新值到当前值,n可以大于nModified

update.nModified

更新的文档数量。如果更新操作没有改变文档,例如将字段的值设置为当前值,nModified可以小于n

注意

如果匹配的文档子集被更新,例如,当更新会导致某些文档失败模式验证时,update 命令返回的nModified值可能不准确。

update.upserted

一个包含通过具有upsert: true的更新插入的每个文档信息的文档数组。

每个文档包含以下信息

update.upserted.index

一个整数,用于标识在updates数组中使用upsert:true语句的更新,使用零基于索引。

update.upserted._id

添加文档的_id值。

update.writeErrors

一个包含有关更新操作期间遇到的任何错误信息的文档数组。该writeErrors数组包含每个出现错误的更新语句的错误文档。

每个错误文档包含以下字段

update.writeErrors.index

一个整数,用于标识在 updates 数组中使用的更新语句,索引从0开始。

update.writeErrors.code

一个整数值,用于标识错误。

update.writeErrors.errmsg

错误的描述。

update.writeConcernError

描述与写入关注点相关的错误的文档。

变更在版本7.1: 当在 update 上执行 mongos 时,即使发生一个或多个写入错误,也会始终报告写入关注点错误。

在之前的版本中,写入错误的发生可能导致 update 不报告写入关注点错误。

writeConcernError 文档包含以下字段

update.writeConcernError.code

标识写入关注点错误原因的整数值。

update.writeConcernError.errmsg

描述写入关注点错误原因的描述。

update.writeConcernError.errInfo.writeConcern

用于相应操作的写关注对象。有关写关注对象字段的信息,请参阅写关注规范。

写关注对象还可以包含以下字段,指示写关注的来源

update.writeConcernError.errInfo.writeConcern.provenance

指示写关注来源的字符串值(称为写关注provenance)。以下表格显示了此字段的可能值及其含义

来源
描述
clientSupplied
写关注是在应用程序中指定的。
customDefault
写关注来源于自定义定义的默认值。请参阅setDefaultRWConcern
getLastErrorDefaults
写关注来源于副本集的settings.getLastErrorDefaults字段。
implicitDefault
在所有其他写关注规范缺失的情况下,写关注来源于服务器。

除了上述特定于更新的返回字段之外,db.runCommand()还包括其他信息

  • 对于副本集:optimeelectionId$clusterTimeoperationTime

  • 对于分片集群:operationTime$clusterTime

有关这些字段的详细信息,请参阅db.runCommand 响应

以下是一个成功执行的update命令返回的示例文档,该命令执行了upsert操作

{
"ok" : 1,
"nModified" : 0,
"n" : 1,
"upserted" : [
{
"index" : 0,
"_id" : ObjectId("52ccb2118908ccd753d65882")
}
]
}

以下是一个示例文档,展示了包含三个更新语句的大批量更新操作的结果,其中一条更新语句成功执行,另外两条更新语句遇到错误。

{
"ok" : 1,
"nModified" : 1,
"n" : 1,
"writeErrors" : [
{
"index" : 1,
"code" : 16837,
"errmsg" : "The _id field cannot be changed from {_id: 1.0} to {_id: 5.0}."
},
{
"index" : 2,
"code" : 16837,
"errmsg" : "The _id field cannot be changed from {_id: 2.0} to {_id: 6.0}."
},
]
}

返回

resetError