对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。
Docs 菜单

db. 集合.updateMany()(mongosh方法)

带驱动程序的 MongoDB

This page documents a mongosh method. To see the equivalent method in a MongoDB driver, see the corresponding page for your programming language:
db.collection.updateMany(filter, update, options)

更新与收集的指定过滤器匹配的所有文档。

此方法可用于以下环境中托管的部署:

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

注意

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

updateMany()方法采用以下形式:

db.collection.updateMany(
<filter>,
<update>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string>,
let: <document>,
maxTimeMS: <int>,
bypassDocumentValidation: <boolean>
}
)

updateMany() 方法采用以下参数:

Parameter
类型
说明

文档

更新的选择条件。可以使用与 find() 方法中相同的查询选择器

指定一个空文档 { } 以更新收集中的所有文档。

文档或管道

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

仅包含以下聚合阶段:

有关更多信息,请参阅使用 聚合管道 更新。

要使用替换文档进行更新,请参阅 db.collection.replaceOne()

upsert

布尔

Optional. When true, updateMany() either:

  • 如果没有文档与 filter 匹配,则创建一个新文档。有关详细信息,请参阅更新或插入行为

  • 更新与 filter 匹配的文档。

要避免多次更新或插入,请确保 filter 字段具有唯一索引。

默认值为 false

writeConcern

文档

可选。表达写关注的文档。省略以使用默认写关注。

如果是在事务中运行,则请勿显式设置此操作的写关注。要将写关注与事务一起使用,请参阅事务和写关注。

collation

文档

可选。

可选。指定用于操作的排序规则

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

排序规则选项的语法如下:

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

指定排序规则时,locale 字段为必填字段;所有其他排序规则字段均为可选字段。有关字段的说明,请参阅排序规则文档

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

如果没有为收集或操作指定排序规则,MongoDB 将使用先前版本中使用的简单二进制比较来进行字符串比较。

您不能为一个操作指定多个排序规则。例如,您不能为每个字段指定不同的排序规则,或者如果执行带排序的查找,则不能使用一种排序规则进行查找而另一种排序规则进行排序。

arrayFilters

阵列

选修的。大量过滤器文档,用于确定针对大量字段的更新操作要修改哪些大量元素。

在更新文档中,使用 $[<identifier>] 筛选后的位置运算符来定义标识符,然后在数组筛选文档中引用该标识符。如果更新文档中未包含某一标识符,则无法获得该标识符的数组筛选文档。

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

您可以在更新文档中多次包含相同的标识符;但对于更新文档中的每个不同标识符 ($[identifier]),您必须准确指定一个对应的数组筛选器文档。也就是说,不能为同一个标识符指定多个数组筛选器文档。例如,如果更新语句包含标识符 x(可能多次),则不能为 arrayFilters 指定以下内容,其中包括 x 的 2 个单独的筛选器文档:

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

For examples, see Specify arrayFilters for an Array Update Operations.

文档或字符串

Optional. A document or string that specifies the index to use to support the query predicate.

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

如果指定不存在的索引,则操作出错。

For an example, see Specify hint for Update Operations.

文档

可选。

指定包含变量列表的文档。这样可以将变量与查询文本分开,从而提高命令的可读性。

文档语法为:

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

变量设置为表达式返回的值,并且之后不能再进行更改。

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

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

有关使用 let 和变量的完整示例,请参阅使用 let 变量进行更新

整型

可选。指定更新操作在超时之前运行的时间限制(以毫秒为单位)。

布尔

可选。启用 insert 可在此操作过程中绕过模式验证。这样就可以插入不符合验证要求的文档。

该方法返回包含以下内容的文档:

  • 如果操作使用写关注来运行,则布尔值 acknowledgedtrue;如果已禁用写关注,则为 false

  • matchedCount 包含匹配文档的数量

  • modifiedCount 包含已修改文档的数量

  • upsertedId ,包含用于已更新或插入的文档的 _id

  • upsertedCount 包含更新或插入文档的数量

在使用 authorization 运行的部署中,用户必须具有包含以下特权的访问权限:

  • update 针对指定集合的操作。

  • find 针对指定集合的操作。

  • insert 如果操作导致更新插入,则对指定收集执行操作。

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

updateMany() 查找集合中与 filter 匹配的所有文档,并应用 update 参数指定的修改。

updateMany() 单独修改每个文档。 每次文档写入都是一个原子操作,但updateMany() 作为一个整体不是原子操作。如果您的使用案例需要写入多个文档的原子性,请使用事务。

如果单个文档更新失败,则保留失败之前写入的所有文档更新,但不会更新任何剩余的匹配文档。有关此行为的详细信息,请参阅多次更新失败。

提示

Sharded Collections for more information about updateMany() behavior in sharded collections.

  • updateMany() 只应用于幂等操作。

如果 upsert: true 且没有文档与 filter 匹配,db.collection.updateMany() 将基于 filterupdate 参数创建一个新文档。

If you specify upsert: true on a sharded collection, you must include the full shard key in the filter. For information about db.collection.updateMany() behavior in sharded collections, see Sharded Collections.

请参阅使用 Upsert 更新多个文档。

对于修改规范,db.collection.updateMany() 方法可接受仅含有要执行的更新操作符表达式的文档。

例如:

db.collection.updateMany(
<query>,
{ $set: { status: "D" }, $inc: { quantity: 2 } },
...
)

db.collection.updateMany() 方法可以接受指定要执行的修改的聚合管道 [ <stage1>, <stage2>, ... ]。该管道可以由以下阶段组成:

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

例如:

db.collection.updateMany(
<query>,
[
{ $set: { status: "Modified", comments: [ "$misc1", "$misc2" ] } },
{ $unset: [ "misc1", "misc2" ] }
]
...
)

注意

在此管道中, $set$unset 是聚合阶段,不是更新操作符。聚合阶段$set$unset为文档添加新字段,并且不修改现有字段值。

有关更新操作符的更多信息,请参阅$set$unset

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

如果更新操作更改了文档大小,则操作将失败。

从 MongoDB 5.1 开始,updateMany() 方法可用于 时间序列集合

更新命令必须满足以下要求:

  • 您只能匹配 metaField 字段值。

  • 您只能修改 metaField 字段值。

  • 您的更新文档只能包含更新操作符表达式。

  • Your update command must not limit the number of documents to be updated. Set multi: true or use the updateMany() method.

  • 更新命令不得设置 upsert: true。

updateMany() 与分片的一起使用时会表现出以下行为:

  • updateMany() 包含 upsert: true 的操作必须在 filter 中包含完整的分片键。

  • If you attempt to run updateMany() during a Range Migration or a shard key value update, the operation can miss documents in some scenarios. To ensure all documents are updated, use idempotent updates and rerun the command until no further updates are applied. For more information on idempotent updates with updateMany(), see Idempotent Updates.

  • 如果updateMany()在事务之外运行,针对多个分片的操作会将该操作广播到集群中的所有分片。

  • 如果 updateMany() 在ACID 事务中运行,则针对多个分片的操作仅针对相关分片。

updateMany()db.collection.explain() 不兼容。

db.collection.updateMany() 可用于分布式事务。

重要

在大多数情况下,与单文档写入操作相比,分布式事务会产生更高的性能成本,并且分布式事务的可用性不应取代有效的模式设计。在许多情况下,非规范化数据模型(嵌入式文档和数组)仍然是数据和使用案例的最佳选择。换言之,对于许多场景,适当的数据建模将最大限度地减少对分布式事务的需求。

有关其他事务使用注意事项(如运行时间限制和 oplog 大小限制),另请参阅生产注意事项

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

db.collection.updateMany() 可在现有集合或不存在集合上运行 upsert: true。如果在不存在的集合上运行,该操作将创建集合。

如果是在事务中运行,则请勿显式设置此操作的写关注。要将写关注与事务一起使用,请参阅事务和写关注。

updateMany() 为每个成功更新的文档在oplog (操作日志)中添加一个条目。如果没有文档更新,则 updateMany() 不会向oplog添加条目。

本页上的示例使用sample_mflix示例数据集中的数据。有关如何将此数据集加载到自管理MongoDB 部署中的详细信息,请参阅加载示例数据集。如果对示例数据库进行了任何修改,则可能需要删除并重新创建数据库才能运行本页上的示例。

sample_mflix.movies集合包含具有 IMDB 评级的电影。此幂等更新执行以下操作:

  • 匹配 IMDB 评分小于 3.0 的所有电影

  • 将这些评分递增 0.5

  • ratingBoosted字段设置为 true

db.movies.updateMany(
{ "imdb.rating": { $lt: 3, $type: "number" }, ratingBoosted: { $ne: true } },
{ $inc: { "imdb.rating": 0.5 }, $set: { ratingBoosted: true } }
)

updateMany() 单独修改匹配的电影文档。单个文档更新是原子操作,但 updateMany() 操作作为一个整体不是原子操作。

如果该操作无法更新所有匹配的文档,您可以安全地重新运行幂等命令,直到没有其他文档与指定的过滤匹配。 在这种情况下,每个文档的 imdb.rating字段仅更新一次,无论重试多少次,因为该命令是幂等的。

sample_mflix.movies集合包含具有 num_mflix_comments字段的电影。

以下操作会查找所有评论超过 100 的电影,并为这些电影添加 popular 标志:

db.movies.updateMany(
{ num_mflix_comments: { $gt: 100 } },
{ $set: { "popular" : true } }
)

db.collection.updateMany() can use an aggregation pipeline to express a more complex update, such as a conditional update based on current field values. For the supported pipeline stages, see Update with an Aggregation Pipeline.

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

此管道:

  • 将 IMDB 和 Tomatoes 收视率合并到新的 combinedRatings数组字段中

  • 设置 ratingsUpdated字段

  • 删除所有匹配文档的原始 imdb.ratingtomatoes.viewer.rating 字段

db.movies.updateMany(
{ year: { $gte: 2010, $lte: 2019 } },
[
{ $set: {
combinedRatings: [ "$imdb.rating", "$tomatoes.viewer.rating" ],
ratingsUpdated: "$$NOW"
} },
{ $unset: [ "imdb.rating", "tomatoes.viewer.rating" ] }
]
)

注意

在此管道中, $set$unset 是聚合阶段,不是更新操作符。聚合阶段$set$unset为文档添加新字段,并且不修改现有字段值。

有关更新操作符的更多信息,请参阅$set$unset

第一个阶段:

$set 阶段:

  • 创建一个新的数组字段combinedRatings,其元素是 imdb.ratingtomatoes.viewer.rating 字段的当前内容

  • 将字段 ratingsUpdated 设置为聚合变量 NOW 的值。

第二阶段
$unset 阶段删除 imdb.ratingtomatoes.viewer.rating 字段。

执行该命令后,2010 中的匹配电影将具有一个 combinedRatings数组,其中包含评分值和时间戳。

使用聚合管道,您可以使用计算出的组合评分分数(IMDB 和 Tomatoes 观看者评分的平均值)更新2010 中的电影,并根据该分数分配字母等级。

db.movies.updateMany(
{
year: { $gte: 2010, $lte: 2019 },
"imdb.rating": { $exists: true },
"tomatoes.viewer.rating": { $exists: true }
},
[
{ $set: {
combinedScore: { $trunc: [
{ $avg: [ "$imdb.rating", "$tomatoes.viewer.rating" ] },
1
] },
scoreUpdated: "$$NOW"
} },
{ $set: {
ratingGrade: { $switch: {
branches: [
{ case: { $gte: [ "$combinedScore", 8 ] }, then: "A" },
{ case: { $gte: [ "$combinedScore", 6 ] }, then: "B" },
{ case: { $gte: [ "$combinedScore", 4 ] }, then: "C" },
{ case: { $gte: [ "$combinedScore", 2 ] }, then: "D" }
],
default: "F"
} }
} }
]
)

注意

在此管道中, $set$unset 是聚合阶段,不是更新操作符。聚合阶段$set$unset为文档添加新字段,并且不修改现有字段值。

有关更新操作符的更多信息,请参阅$set$unset

第一个阶段:

$set 阶段:

  • 根据 imdb.ratingtomatoes.viewer.rating 字段的平均值计算新字段combinedScore$avg$avg有关 聚合操作符的详细信息,请参阅$trunc $trunc,有关 截断聚合操作符的详细信息,请参阅 。

  • 将字段 scoreUpdated 设置为聚合变量 NOW 的值。

第二阶段
$set 阶段根据上一阶段计算的 combinedScore 字段计算新字段 ratingGrade。有关 $switch 聚合操作符的更多信息,请参阅 $switch

执行该命令后,匹配的电影将具有组合分数和字母等级。

以下操作会更新 2020 之后上映且由 Christopher Nolan 执导的所有电影:

db.movies.updateMany(
{
year: { $gt: 2020 },
directors: "Christopher Nolan"
},
{ $set: { "upcomingRelease": true } },
{ upsert: true }
)

在此示例中,由于没有文档与过滤器匹配,且 upserttrue,因此 updateMany 会插入一个新文档,其中包含生成的 _id 以及来自 filter 的相等条件和 update 修饰符。

给定一个三成员副本集,以下操作指定 majorityw100wtimeout

db.movies.updateMany(
{ title: "The Godfather" },
{ $inc: { num_mflix_comments: 10 }, $set: { trending: true } },
{ w: "majority", wtimeout: 100 }
)

如果确认花费的时间超过 wtimeout 限制, MongoDB将引发异常。

下表解释了 errInfo.writeConcern.provenance 的可能值:

来源
说明

clientSupplied

应用程序中指定了写关注。

customDefault

写入关注源自自定义的默认值。请参阅 setDefaultRWConcern

getLastErrorDefaults

写关注源自副本集的 settings.getLastErrorDefaults 字段。

implicitDefault

在没有所有其他写入关注规范的情况下,写入关注源自服务器。

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

以下操作使用不区分大小写的排序规则来匹配具有小写和大写任意组合的类型为“戏剧”的电影。

db.movies.updateMany(
{ genres: "drama" },
{ $set: { genreNormalized: true } },
{ collation: { locale: "en", strength: 1 } }
)

更新数组字段时,您可以指定 arrayFilters 确定要更新哪些数组元素。

通过组合各种收视分数为某些电影添加 ratings数组:

db.movies.updateMany(
{
"imdb.rating": { $exists: true },
"tomatoes.viewer.rating": { $exists: true },
"tomatoes.critic.rating": { $exists: true },
year: { $gte: 2010, $lte: 2015 }
},
[
{ $set: {
ratings: [
{ $multiply: ["$imdb.rating", 10] },
{ $multiply: ["$tomatoes.viewer.rating", 10] },
{ $multiply: ["$tomatoes.critic.rating", 10] }
]
} }
]
)

要更新ratings数组中大于或等于 100 的所有评分,请使用带有 arrayFilters 选项的过滤器位置操作符$[<identifier>]

db.movies.updateMany(
{ ratings: { $gte: 100 } },
{ $set: { "ratings.$[element]" : 100 } },
{ arrayFilters: [ { "element": { $gte: 100 } } ] }
)

操作完成后,ratings 数组中所有大于或等于 100 的评分值都将设立为 100。

为具有单独评级来源的电影添加 ratingDetails数组:

db.movies.updateMany(
{
"imdb.rating": { $exists: true },
"tomatoes.viewer.rating": { $exists: true },
year: { $gte: 2010, $lte: 2012 }
},
[
{ $set: {
ratingDetails: [
{ source: "imdb", score: "$imdb.rating", weight: 10 },
{ source: "tomatoes_viewer", score: "$tomatoes.viewer.rating", weight: 8 },
{ source: "tomatoes_critic", score: "$tomatoes.critic.rating", weight: 7 }
]
} }
]
)

要将 ratingDetails 数组中分数大于或等于 8 的所有元素的 weight 字段的值修改为 10,请将筛选后的位置操作符 $[<identifier>]arrayFilters 结合使用:

db.movies.updateMany(
{ ratingDetails: { $exists: true } },
{ $set: { "ratingDetails.$[elem].weight" : 10 } },
{ arrayFilters: [ { "elem.score": { $gte: 8 } } ] }
)

操作完成后,所有分数小于或等于 8 的评级源的权重设立为 10。

在集合上创建以下索引:

db.movies.createIndex( { rated: 1 } )

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

注意

如果指定不存在的索引,则操作出错。

db.movies.updateMany(
{ "num_mflix_comments": { $lte: 5 }, "rated": "G" },
{ $set: { "familyFriendly": true } },
{ hint: { rated: 1 } }
)

要查看是否使用提示索引,运行 $indexStats 管道:

db.movies.aggregate( [ { $indexStats: { } }, { $sort: { name: 1 } }, { $match: {key: { rated: 1 } } } ] )

在版本8.1.2中进行了更改。

db.collection.updateMany() 在分片集群中的mongos上执行时,即使出现一个或多个其他错误,响应中也始终会报告 writeConcernError。在以前的版本中,其他错误有时会导致 db.collection.updateMany() 不报告写关注(write concern)错误。

示例,如果文档验证失败,触发 DocumentValidationFailed 错误,并且还发生写关注(write concern)错误,则 DocumentValidationFailed 错误和 writeConcernError 都会在响应的顶级字段中返回。

从 MongoDB 7.0 开始,您可以使用新的 USER_ROLES 系统变量来返回用户角色

本部分中的示例展示了包含医疗信息的集合中的字段更新。该示例从 USER_ROLES 系统变量中读取当前用户角色,并且仅在用户具有特定角色时才执行更新。

要使用系统变量,请将$$添加到变量名称的开头。将USER_ROLES系统变量指定为$$USER_ROLES

该示例创建这些用户:

  • James 角色为 Billing

  • Michelle 角色为 Provider

执行以下步骤以创建角色、用户和集合:

1

创建名为 BillingProvider 的角色,并赋予所需权限和资源。

运行:

db.createRole( { role: "Billing", privileges: [ { resource: { db: "test",
collection: "medicalView" }, actions: [ "find" ] } ], roles: [ ] } )
db.createRole( { role: "Provider", privileges: [ { resource: { db: "test",
collection: "medicalView" }, actions: [ "find" ] } ], roles: [ ] } )
2

创建名为 JamesMichelle 的用户,并赋予所需角色。

db.createUser( {
user: "James",
pwd: "js008",
roles: [
{ role: "Billing", db: "test" }
]
} )
db.createUser( {
user: "Michelle",
pwd: "me009",
roles: [
{ role: "Provider", db: "test" }
]
} )
3

运行:

db.medical.insertMany( [
{
_id: 0,
patientName: "Jack Jones",
diagnosisCode: "CAS 17",
creditCard: "1234-5678-9012-3456"
},
{
_id: 1,
patientName: "Mary Smith",
diagnosisCode: "ACH 01",
creditCard: "6541-7534-9637-3456"
}
] )

以角色为 ProviderMichelle 身份登录,然后执行更新:

1

运行:

db.auth( "Michelle", "me009" )
2

运行:

// Attempt to update many documents
db.medical.updateMany(
// User must have the Provider role to perform the update
{ $expr: { $ne: [ {
$setIntersection: [ [ "Provider" ], "$$USER_ROLES.role" ] }, []
] } },
// Update diagnosisCode
{ $set: { diagnosisCode: "ACH 02"} }
)

前面的示例使用 $setIntersection 返回文档,其中,"Provider" 字符串与 $$USER_ROLES.role 中的用户角色之间的交集不为空。Michelle 的角色为 Provider,因此,将执行更新。

接下来,以不具有 Provider 角色的 James 身份登录,并尝试执行相同更新:

1

运行:

db.auth( "James", "js008" )
2

运行:

// Attempt to update many documents
db.medical.updateMany(
// User must have the Provider role to perform the update
{ $expr: { $ne: [ {
$setIntersection: [ [ "Provider" ], "$$USER_ROLES.role" ] }, []
] } },
// Update diagnosisCode
{ $set: { diagnosisCode: "ACH 02"} }
)

前面的示例没有更新任何文档。