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

db.集合。 更新()(mongosh方法)

重要

已弃用的 mongosh 方法

This method is deprecated in mongosh. For alternative methods, see Compatibility Changes with Legacy mongo Shell.

db.collection.update(query, update, options)

修改集合中的一个或多个现有文档。该方法可以修改现有文档的特定字段,也可以完全替换现有文档,具体取决于更新参数

By default, the db.collection.update() method updates a single document. Include the option multi: true to update all documents that match the query criteria.

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

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

注意

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

在版本5.0中进行了更改。

db.collection.update()方法采用以下形式:

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

db.collection.update() 方法采用以下参数:

Parameter
类型
说明

文档

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

When you execute an update() with upsert: true and the query matches no existing document, MongoDB will refuse to insert a new document if the query specifies conditions on the _id field using dot notation.

文档或管道

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

仅包含 <field1>: <value1> 对。

仅包含以下聚合阶段:

有关详细信息和示例,请参阅 Oplog 条目

布尔

Optional. When true, update() either:

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

  • 更新与 query 匹配的单份文档。

如果 upsertmulti 均为 true,并且没有文档与查询匹配,则更新操作仅插入单个文档。

为避免多次更新或插入,请确保 query 字段具有唯一索引。有关示例,请参阅使用重复值进行更新或插入

默认值为 false;即,在未找到匹配项时插入新文档。

布尔

可选。如果设为 true,则更新所有符合 query 条件的文档。如果设为 false,则更新一个文档。默认值为 false。有关其他信息,请参阅更新多个文件示例

文档

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

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

有关使用writeConcern的示例,请参阅覆盖默认写关注

文档

可选。

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

有关使用 collation 的示例,请参阅指定排序规则

阵列

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

In the update document, use the $[<identifier>] to define an identifier to update only those array elements that match the corresponding filter document in the arrayFilters.

如果更新文档中未包含某一标识符,则无法获得该标识符的数组筛选文档。

For examples, see 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 操作符中访问该变量。

For a complete example using let and variables, see Use Variables in let.

整型

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

布尔

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

该方法返回包含操作状态的 WriteResult 文档。

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

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

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

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

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

如果设置multi: true,请仅将update()方法用于幂等操作。

Attempting to use the $expr operator with the upsert flag set to true generates an error.

要在分片集合上使用 db.collection.update()multi: false,必须在 _id 字段中包含精确匹配,或以单个分片为目标(如包含分片键)。

db.collection.update() 执行更新操作(而非文档替换操作)时,db.collection.update() 可以将多个分片作为目标。

替换文档操作会首先尝试使用查询过滤器定位单个分片。该操作如果无法通过查询过滤器定位单个分片,则会尝试通过替换文档定位。

在早期版本中,该操作会尝试使用替换文档定位。

For a db.collection.update() operation that includes upsert: true and is on a sharded collection, you must include the full shard key in the filter:

  • 用于更新操作。

  • 进行替换文档操作。

但是,分片集合中的文档可能缺少分片键字段。要定位缺失分片键的文档,可将 null 等值匹配与其他过滤条件(例如针对 _id 字段)结合使用。例如:

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

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

要使用 db.collection.update() 修改现有的分片键值:

  • 必须mongos 上运行。请勿直接对分片发出此操作。

  • 必须事务中运行,或者以可重试写入的形式运行。

  • 必须指定 multi: false

  • 必须在完整分片键上包含相等查询筛选条件

提示

由于缺失的键值是作为 null 相等匹配的一部分返回的,因此为避免更新空值键,请酌情纳入其他查询条件(例如 _id 字段)。

See also upsert on a Sharded Collection.

分片集合中的文档可能缺少分片键字段。要使用 db.collection.update() 来设置文档的缺失分片键,必须mongos 上运行。请勿直接对分片发出操作。

此外,以下要求也适用:

任务
要求

若要设为 null

  • 可以指定 multi: true

  • 如果 upsert: true,则需使用针对完整分片键的相等筛选器。

要设置为非 null

  • 必须事务中或作为可重试写入执行。

  • 必须指定 multi: false

  • 如果满足以下任一条件,则需使用针对完整分片键的相等筛选器:

    • upsert: true,或

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

提示

由于缺失的键值是作为 null 相等匹配的一部分返回的,因此为避免更新空值键,请酌情纳入其他查询条件(例如 _id 字段)。

另请参阅:

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

重要

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

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

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

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

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

如果 db.collection.update() 操作成功更新了文档,则该操作会为 oplog(操作日志)添加一个条目。如果操作失败或者未找到要更新的文档,则该操作不会为 oplog 添加条目。

When you execute an update() with upsert: true and the query matches no existing document, MongoDB will refuse to insert a new document if the query specifies conditions on the _id field using dot notation.

此限制确保 _id 文档中嵌入的字段顺序定义明确,并且不受查询中指定顺序的约束。

如果尝试以这种方式插入文档, MongoDB会引发错误。

除非有唯一索引来防止重复,否则 upsert 可能会创建重复的文档。

如果所有 db.collection.update() 操作在任何客户端成功插入数据之前完成查询阶段,并且 name字段上没有唯一索引,则每个 db.collection.update() 操作都可能导致插入,从而使用 name: Andy 创建多个文档。

name字段上的唯一索引可确保只创建一个文档。使用唯一索引后,多个 db.collection.update() 操作现在会表现出以下行为:

  • 正好一个 db.collection.update() 操作成功插入一个新的
    文档。
  • 其他 db.collection.update() 操作要么更新新插入的

    文档,否则会因唯一键冲突而失败。

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

    • 目标集合具有唯一索引,该索引会导致
      重复键错误。
    • 更新操作不是 updateManymulti
      false.
    • 更新匹配条件为:

      • 单个相等谓词。例如 { "fieldA" : "valueA" }

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

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

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

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

您可以在更新文档中多次包含相同的标识符;但是,对于更新文档中的每个非重复标识符 ($[identifier]),您必须指定准确一个对应的数组过滤器文档。也就是说,不能为同一标识符指定多个数组过滤器文档。但是,您可以在单个过滤文档中对同一标识符指定复合条件

注意

arrayFilters 不适用于使用聚合管道的更新。

db.collection.update() 方法会返回一个 WriteResult() 对象,其中包含此操作的状态。成功后,WriteResult() 对象将包含匹配查询条件的文档数量、更新插入的文档数量以及修改的文档数量。

如果 db.collection.update() 方法遇到写关注(write concern)错误,结果包括 WriteResult.writeConcernError 字段。

下表解释了 WriteResult.writeConcernError.provenance 的可能值:

来源
说明

clientSupplied

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

customDefault

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

getLastErrorDefaults

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

implicitDefault

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

如果 db.collection.update() 方法遇到非写关注(write concern)错误,结果将包括 WriteResult.writeError 字段。

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

如果 <update> 文档包含更新操作符修饰符,例如使用 $set 修饰符,则:

  • <update> 文档只能包含更新操作符表达式。

  • db.collection.update() 方法只更新文档中的相应字段。

    • 要将嵌入式文档或数组作为整体进行更新,请指定该字段的替换值。

    • 要更新嵌入式文档或数组中的特定字段,请使用点符号来指定字段。

db.movies.update(
{ title: "The Godfather" },
{
$inc: { "tomatoes.viewer.numReviews": 1 },
$set: {
"tomatoes.viewer.meter": 99
}
}
)
/* Corresponds to the following SQL statement:
* UPDATE movies
* SET tomatoes_viewer_numReviews = tomatoes_viewer_numReviews + 1,
* tomatoes_viewer_meter = 99
* WHERE title = "The Godfather"
*/

在此操作中:

  • { title: "The Godfather" }<query> 参数指定要更新的文档

  • $inc 操作符递增 tomatoes.viewer 嵌入式文档中的 numReviews 字段

  • $set 操作符更新 tomatoes.viewer 嵌入式文档中的 meter 字段。

如果 query 参数匹配到多个文档,此操作将只更新一个匹配文档。要更新多个文档,必须将 multi 选项设置为 true

以下操作使用 $push 更新操作符将值附加到 genres 数组。

db.movies.update(
{ title: "The Matrix" },
{
$push: { genres: "Thriller" }
}
)

更新后,genres数组将包含新值。

提示

$push

以下操作使用$unset操作符从“教父”文档中删除metacritic字段。

db.movies.update(
{ title: "The Godfather" },
{ $unset: { metacritic: "" } }
)
/* $unset is similar (but not identical) to the following SQL
command which removes the ``metacritic`` field from the ``movies``
table
* UPDATE movies
* SET metacritic = NULL
* WHERE title = "The Godfather"
*/

更新后,metacritic字段将被删除。

如果 multi 设置为 true,则 db.collection.update() 方法会更新符合 <query> 标准的所有文档。multi 更新操作可与其他读/写入操作交错进行。

以下操作将标题为“教父”或“黑客帝国”的文档的 test_field字段设置为 true

db.movies.update(
{ title: { $in: ["The Godfather", "The Matrix"] } },
{ $set: { test_field: true } },
{ multi: true }
)
/* Corresponds to the following SQL statement:
* UPDATE movies
* SET test_field = true
* WHERE title IN ('The Godfather', 'The Matrix')
*/

该操作会更新两个匹配的文档。

You cannot specify multi: true when performing a replacement and the update document contains only field:value expressions.

提示

$set

指定选项 upsert: true 时:

  • 如果文档符合查询条件,db.collection.update() 将执行更新。

  • 如果没有文档符合查询条件,db.collection.update() 将插入单个文档。

    注意

    If multiple, identical upserts are issued at roughly the same time, it is possible for update() used with upsert: true to create duplicate documents. See Upsert with Duplicate Values for more information.

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

以下标签页展示了 upsert 修饰符与 update() 的各种用途。

如果没有符合查询条件的文档,且 <update> 参数是替换文档(即仅包含字段和值对),则更新将插入一个包含替换文档的字段和值的新文档。

  • 如果您在查询参数或替换文档中指定 _id 字段,则 MongoDB 将在插入的文档中使用该 _id 字段。

  • 如果您未在查询参数或替换文档中指定 _id 字段,MongoDB 将使用随机生成的 ObjectId 值添加 _id 字段。

    您不能在查询参数和替换文档中指定不同的 _id 字段值。如果这样做,操作将出错。

For example, the following update sets the upsert option to true:

db.movies.update(
{ title: "Test Movie 12345" },
{
$set: {
title: "Test Movie 12345",
year: 2024,
genres: [ "Documentary" ],
rated: "NR"
}
},
{ upsert: true }
)

如果没有与 <query> 参数匹配的文档,则更新操作将插入一个包含替换文档的文档。由于在替换文档或查询文档中未指定 _id字段,因此该操作会为新文档的 _id字段创建一个新的唯一 ObjectId。您可以看到 upsert 反映在操作的 WriteResult 中。

如果没有符合查询条件的文档,且 <update> 参数是带有更新操作符表达式的文档,则该操作将根据 <query> 参数中的等式子句创建基础文档,并应用 <update> 参数中的表达式。

来自<query>比较操作将不包含在新文档中。 如果新文档不包含_id字段, MongoDB将添加带有ObjectId值的_id字段。

For example, the following update sets the upsert option to true:

db.movies.update(
{ title: "Test Movie 67890" }, // Query parameter
{ // Update document
$set: { rated: "PG" },
$setOnInsert: { year: 2024, type: "movie" }
},
{ upsert: true } // Options
)

如果没有符合查询条件的文档,则该操作将插入相应的文档。

If the <update> parameter is an aggregation pipeline, the update creates a base document from the equality clauses in the <query> parameter, and then applies the pipeline to the document to create the document to insert. If the new document does not include the _id field, MongoDB adds the _id field with an ObjectId value.

示例,以下聚合管道会在 movies集合中插入一个新文档,因为不存在与查询筛选条件匹配的现有文档:

db.movies.update(
{ title: "Test Movie ABC123" }, // Query parameter
[ // Aggregation pipeline
{ $set: {
year: 2024,
type: "movie",
rated: "NR",
lastModified: "$$NOW"
} }
],
{ upsert: true } // Options
)

提示

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

以下操作同时指定了 multi 选项和 upsert 选项。如果存在匹配的文档,则该操作将更新所有匹配的文档。如果不存在匹配的文档,则该操作将插入一个新文档。

db.movies.update(
{ title: { $in: ["The Godfather", "The Matrix"] } },
{ $set: { test_upsert_field: true } },
{ upsert: true, multi: true }
)

由于两部电影都存在于集合中,因此该操作会同时更新两份匹配的文档。

如果集合中没有匹配的文档,操作结果将是使用 <query><update> 规范中的字段插入一个文档。例如,考虑以下操作:

db.movies.update(
{ "title": "Test Movie Unique789" },
{ $set: { year: 2024, type: "movie" } },
{ upsert: true, multi: true }
)

该操作将相应的文档插入到 movies集合中。

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

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

以下示例创建了一个将电影标题和年份组合在一起的 displayTitle字段,并通过执行这些操作的聚合管道:

  • 通过连接 titleyear 字段来创建 displayTitle字段

  • 设置 lastModified 时间戳

db.movies.update(
{ title: "The Godfather" },
[
{ $set: {
displayTitle: { $concat: [ "$title", " (", { $toString: "$year" }, ")" ] },
lastModified: "$$NOW"
}
}
]
)

以下示例更新了 2015 上映的电影,以计算 IMDB 和 Tomatoes 评分的组合评分,并根据该分数指定一个等级。

db.movies.update(
{
year: 2015,
"imdb.rating": { $type: "number" },
"tomatoes.viewer.rating": { $type: "number" }
},
[
{ $set: {
combinedScore: {
$round: [
{ $avg: [
{ $multiply: [ "$imdb.rating", 10 ] },
{ $multiply: [ "$tomatoes.viewer.rating", 10 ] }
] },
1
]
},
lastUpdate: "$$NOW"
}
},
{ $set: {
grade: {
$switch: {
branches: [
{ case: { $gte: [ "$combinedScore", 80 ] }, then: "A" },
{ case: { $gte: [ "$combinedScore", 70 ] }, then: "B" },
{ case: { $gte: [ "$combinedScore", 60 ] }, then: "C" },
{ case: { $gte: [ "$combinedScore", 50 ] }, then: "D" }
],
default: "F"
}
}
}
}
],
{ multi: true }
)

注意

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

$set 阶段:

  • 通过计算 IMDB 评分(按 10 缩放)和 Tomatoes 收视率(按 10 缩放)的平均值计算新字段combinedScore,然后四舍五入到小数点后一位。有关更多信息,请参阅 $avg$multiply$round

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

  • 根据 combinedScore 使用 $switch 操作符分配字母等级。

要更新符合指定条件的所有数组元素,请使用 arrayFilters 参数。

以下示例更新其 languages数组中包含 "English" 的所有电影。该操作会将 "English" 替换为 "EN"

db.movies.update(
{ languages: "English" },
{ $set: { "languages.$[element]" : "EN" } },
{
arrayFilters: [ { "element": "English" } ],
multi: true
}
)

您还可以将 arrayFilters 参数与筛选后的位置操作符一起使用,以更新与模式匹配的特定数组元素。

以下示例使用现有集合中的“教父”电影,该集合具有 writers数组。该操作仅更新名称通过附加后缀包含“剧本”的作者。

db.movies.update(
{ title: "The Godfather" },
{ $set: { "writers.$[elem]" : { $concat: [ "$elem", " - UPDATED" ] } } },
{
arrayFilters: [ { "elem": { $regex: /screenplay/ } } ]
}
)

该操作以“教父”文档为目标,仅更新与过滤器条件匹配的数组元素。操作完成后,撰写剧本的编剧会在后面加上“- UPDATED”。

hint 选项指定 MongoDB 用于更新操作的索引。指定索引可确保更新多个文档时查询计划的一致。此示例使用 sample_mflix 数据库中的现有 movies 集合。

首先,在 year字段上创建索引:

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

以下更新操作明确提示使用 { year: 1 }索引来更新2010 -2015 之间的所有电影:

db.movies.update(
{ year: { $gte: 2010, $lte: 2015 } }, // Query parameter
{ $set: { decade: "2010s" } }, // Update document
{ multi: true, hint: { year: 1 } } // Options
)

注意

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

要查看使用的索引,请对操作运行 explain

db.movies.explain().update(
{ title: "The Godfather", year: { $gte: 1970 } },
{ $set: { test_hint_field: true } },
{ hint: { year: 1 } }
)

db.collection.explain().update() 不修改文档。

版本 5.0 中的新增功能。

要定义可在命令中其他位置访问的变量,请使用 let 选项。

注意

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

示例:

  • let 选项中定义两个变量:targetTitle(设立为 "The Matrix")和 newTitle(设立为 "The Matrix Reloaded")

  • 在查询筛选条件中使用 $expr 将文档的 title字段与 $$targetTitle 变量进行比较

  • 使用带有 $set 的聚合管道,将 title字段更新为 $$newTitle 的值

db.movies.update(
{ $expr: { $eq: [ "$title", "$$targetTitle" ] } },
[ { $set: { sequel: "$$sequelTitle" } } ],
{ let : { targetTitle: "The Matrix", sequelTitle: "The Matrix Reloaded" } }
)

以下对副本集的操作指定了写关注 w: 2,其 wtimeout 为 5000 毫秒。该操作要么在写操作传播到主节点和一个辅助节点后返回,要么在 5 秒后超时。

db.movies.update(
{ num_mflix_comments: { $lte: 10 } },
{ $set: { featured: true } },
{
multi: true,
writeConcern: { w: 2, j: true, wtimeout: 5000 }
}
)

在主节点 (primary node in the replica set)和至少一个从节点(secondary node from replica set)(如 w: 2 指定)确认写入后,操作成功完成。

在版本8.1.2中进行了更改。

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

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

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

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

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

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

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

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

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

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

此操作会更新标题以 night 开头的所有电影,并使用 strength: 1 进行不区分大小写的比较:

db.movies.update(
{ title: /^night/i },
{ $set: { updated: true } },
{
collation: { locale: "en", strength: 1 },
multi: true
}
)