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

db.collection.update()

在本页面上

  • 定义
  • 兼容性
  • 语法
  • 访问控制
  • 行为
  • 示例
  • 写入结果

重要

已弃用的mongosh方法

此方法在mongosh中已弃用。有关替代方法,请参阅与遗留mongo Shell的兼容性更改。

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

修改集合中现有文档或文档。此方法可以根据更新参数修改现有文档或文档的特定字段,或者完全替换现有文档。

默认情况下,db.collection.update() 方法更新单个文档。包含选项 multi: true 以更新所有匹配查询条件的文档。

此方法在以下环境中提供

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

注意

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

  • MongoDB 企业版:基于订阅、自主管理的 MongoDB 版本

  • MongoDB 社区版:源代码开放、免费使用且自主管理的 MongoDB 版本

已更改版本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> // Added in MongoDB 5.0
}
)

db.collection.update() 方法接受以下参数

参数
类型
描述
文档

更新的选择标准。提供与 查询选择器 相同的选项,如 find() 方法中所述。

当你使用 upsert: true 执行 update() 并且查询与现有文档不匹配时,如果查询使用点符号指定了 _id 字段的条件,MongoDB 将拒绝插入新文档。

文档或管道

要应用的操作。可以是以下之一

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

仅包含以下聚合阶段

有关详细信息,请参阅 Oplog Entries.

布尔值

可选。当设置为 true 时,update() 将执行以下操作:

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

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

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

为了避免多次 upsert,请确保 query 字段被 唯一索引。有关示例,请参阅 Upsert with Duplicate Values

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

布尔值

可选。如果设置为 true,则更新符合 query 条件的多个文档。如果设置为 false,则更新单个文档。默认值为 false。有关更多信息,请参阅 Update Multiple Documents Examples.

文档

可选。一个文档,表示 write concern。省略以使用默认的写关注 w: "majority"

如果在事务中运行操作,请不要显式设置写关注。有关使用事务的写关注的说明,请参阅 Transactions and Write Concern.

有关使用 writeConcern 的示例,请参阅 Override Default Write Concern.

文档

可选。

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

有关使用 collation 的示例,请参阅 Specify Collation.

数组

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

update document 中,使用 $[<identifier>] 定义一个标识符,以更新匹配 arrayFilters 中相应过滤器文档的数组元素。

如果标识符未包含在更新文档中,则不能为其设置数组过滤器。

例如,请参阅为Array Update Operations指定arrayFilters

文档或字符串

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

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

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

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

文档

可选。

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

文档语法是

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

变量被设置为表达式返回的值,之后不能更改。

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

要使用变量过滤结果,必须在$expr运算符内部访问变量。

有关使用let和变量的完整示例,请参阅let中使用变量。

版本5.0.

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

在运行 authorization 配置的部署中,用户必须具备以下权限访问

  • 在指定的集合上执行 update 操作。

  • 在指定的集合上执行 find 操作。

  • 如果操作结果是 upsert,则在指定的集合上执行 insert 操作。

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

尝试使用带有 upsert 标志设置为 true$expr 操作符将引发错误。

要在分片集合上使用 db.collection.update() 并设置 multi: false,您必须在 _id 字段上包含精确匹配或针对单个分片(例如通过包含分片键)进行目标。

db.collection.update() 执行更新操作(而不是文档替换操作)时,db.collection.update() 可以针对多个分片。

提示

另请参阅

替换文档操作尝试首先通过查询过滤器定位单个分片。如果操作无法通过查询过滤器定位单个分片,它将尝试通过替换文档进行定位。

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

对于包含 upsert: true 并位于分片集合上的 db.collection.update() 操作,必须在 filter 中包含完整的分片键。

  • 对于更新操作。

  • 对于替换文档操作。

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

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

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

要使用 db.collection.update():

提示

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

另请参阅 upsert on a Sharded Collection.

分片集合中的文档可能会缺少分片键字段。为了使用db.collection.update()来设置文档的缺失分片键,您必须在mongos上运行。不要在分片上直接执行操作。

此外,以下要求也适用

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

  • 如果upsert: true,则需要全分片键的等值过滤器。

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

  • 必须指定multi: false

  • 如果以下任一条件成立,则需要全分片键的等值过滤器:

    • upsert: true,或

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

提示

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

另请参阅

db.collection.update()可以在分布式事务中使用。

重要

在大多数情况下,分布式事务比单文档写入的成本更高,分布式事务的可用性不应成为有效模式设计的替代品。对于许多场景,非规范化数据模型(嵌入文档和数组)将继续是您数据和用例的最佳选择。也就是说,对于许多场景,适当地建模您的数据将最大限度地减少对分布式事务的需求。

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

您可以在分布式事务中创建集合和索引,前提是事务不是一个跨分片写事务。

带有 upsert: truedb.collection.update() 可以在一个现有的集合或一个不存在的集合上运行。如果在非现有集合上运行,操作将创建该集合。

如果在事务中运行操作,请不要显式设置写关注。有关使用事务的写关注的说明,请参阅 Transactions and Write Concern.

如果 db.collection.update() 操作成功更新了一个或多个文档,则该操作会在 oplog(操作日志)中添加一个条目。如果操作失败或找不到任何文档进行更新,则该操作不会在 oplog 中添加条目。

以下选项卡展示了各种常见的 update() 操作。

mongosh 中,创建一个包含以下文档的 books 集合。此命令首先从 books 集合中删除所有先前存在的文档

db.books.remove({});
db.books.insertMany([
{
"_id" : 1,
"item" : "TBD",
"stock" : 0,
"info" : { "publisher" : "1111", "pages" : 430 },
"tags" : [ "technology", "computer" ],
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ],
"reorder" : false
},
{
"_id" : 2,
"item" : "XYZ123",
"stock" : 15,
"info" : { "publisher" : "5555", "pages" : 150 },
"tags" : [ ],
"ratings" : [ { "by" : "xyz", "rating" : 5 } ],
"reorder" : false
}
]);

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

  • <update> 文档必须仅包含 更新运算符 表达式。

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

    • 要更新嵌入式文档或整个数组,指定该字段的替换值。

    • 要更新嵌入式文档或数组中的特定字段,使用 点表示法 指定该字段。

db.books.update(
{ _id: 1 },
{
$inc: { stock: 5 },
$set: {
item: "ABC123",
"info.publisher": "2222",
tags: [ "software" ],
"ratings.1": { by: "xyz", rating: 3 }
}
}
)

在此操作中

  • { _id: 1 }<query> 参数指定要更新的文档

  • $inc 运算符增加 stock 字段,并且

  • $set 运算符替换 item 字段的值

    • info 嵌套文档中的 publisher 字段

    • 字段,以及

    • tags 字段

    • ratings 数组的第二个元素。

更新后的文档如下

{
"_id" : 1,
"item" : "ABC123",
"stock" : 5,
"info" : { "publisher" : "2222", "pages" : 430 },
"tags" : [ "software" ],
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ],
"reorder" : false
}

此操作对应以下 SQL 语句

UPDATE books
SET stock = stock + 5
item = "ABC123"
publisher = 2222
pages = 430
tags = "software"
rating_authors = "ijk,xyz"
rating_values = "4,3"
WHERE _id = 1

如果 query 参数匹配多个文档,则操作仅更新一个匹配的文档。要更新多个文档,将 multi 选项设置为 true

提示

另请参阅

以下操作使用$push更新运算符将新对象追加到ratings数组中。

db.books.update(
{ _id: 2 },
{
$push: { ratings: { "by" : "jkl", "rating" : 2 } }
}
)

更新后的文档如下

{
"_id" : 2,
"item" : "XYZ123",
"stock" : 15,
"info" : {
"publisher" : "5555",
"pages" : 150
},
"tags" : [ ],
"ratings" : [
{ "by" : "xyz", "rating" : 5 },
{ "by" : "jkl", "rating" : 2 }
],
"reorder" : false
}

提示

另请参阅

以下操作使用$unset运算符从具有{ _id: 1 }的文档中删除tags字段。

db.books.update( { _id: 1 }, { $unset: { tags: 1 } } )

更新后的文档如下

{
"_id" : 1,
"item" : "TBD",
"stock" : 0,
"info" : {
"publisher" : "1111",
"pages" : 430
},
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "lmn", "rating" : 5 } ],
"reorder" : false
}

没有直接对应的SQL语句$unset,但是$unset与以下SQL命令类似,该命令从books表中删除tags字段

ALTER TABLE books
DROP COLUMN tags

提示

另请参阅

如果将 multi 设置为 true,则 db.collection.update() 方法会更新符合 <查询条件> 的所有文档。多文档更新操作可能与其他读写操作交织。

以下操作将所有库存小于或等于 10 的文档的 reorder 字段设置为 true。如果匹配的文档(们)中不存在 reorder 字段,则 $set 操作符会添加该字段并赋予指定值。

db.books.update(
{ stock: { $lte: 10 } },
{ $set: { reorder: true } },
{ multi: true }
)

该集合中的结果文档如下

[
{
"_id" : 1,
"item" : "ABC123",
"stock" : 5,
"info" : {
"publisher" : "2222",
"pages" : 430
},
"ratings" : [ { "by" : "ijk", "rating" : 4 }, { "by" : "xyz", "rating" : 3 } ],
"reorder" : true
}
{
"_id" : 2,
"item" : "XYZ123",
"stock" : 10,
"info" : { "publisher" : "2255", "pages" : 150 },
"tags" : [ "baking", "cooking" ],
"reorder" : true
}
]

此操作对应以下 SQL 语句

UPDATE books
SET reorder=true
WHERE stock <= 10

在执行替换操作时,不能指定 multi: true,且 更新 文档只包含 字段:值 表达式。

提示

另请参阅

当你指定选项 upsert: true:

如果在一个分片集合上指定了upsert: true,则必须在filter中包含完整的分片键。有关分片集合上db.collection.update()的其他行为,请参阅分片集合

以下选项卡展示了使用update()upsert修饰符的各种用法。

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

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

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

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

例如,以下更新将upsert选项设置为true

db.books.update(
{ item: "ZZZ135" }, // Query parameter
{ $set:
{
item: "ZZZ135", stock: 5, tags: [ "database" ] // Replacement document
}
},
{ upsert: true } // Options
)

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

WriteResult({
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : ObjectId("5da78973835b2f1c75347a83")
})

操作将以下文档插入到books集合中(您的ObjectId值将不同)

{
"_id" : ObjectId("5da78973835b2f1c75347a83"),
"item" : "ZZZ135",
"stock" : 5,
"tags" : [ "database" ]
}

如果没有文档匹配查询条件,并且<update>参数是一个包含更新运算符表达式的文档,那么该操作将根据<query>参数中的等价子句创建一个基本文档,并应用<update>参数中的表达式。

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

例如,以下更新将upsert选项设置为true

db.books.update(
{ item: "BLP921" }, // Query parameter
{ // Update document
$set: { reorder: false },
$setOnInsert: { stock: 10 }
},
{ upsert: true } // Options
)

如果没有文档匹配查询条件,则操作将插入以下文档(您的ObjectId值将不同)

{
"_id" : ObjectId("5da79019835b2f1c75348a0a"),
"item" : "BLP921",
"reorder" : false,
"stock" : 10
}

提示

另请参阅

如果<update>参数是一个聚合管道,则更新操作将根据<query>参数中的等价子句创建一个基本文档,然后将管道应用于该文档以创建要插入的文档。如果新的文档不包含_id字段,MongoDB将添加一个具有ObjectId值的_id字段。

例如,以下upsert: true操作指定了一个聚合管道,该管道使用

  • $replaceRoot阶段,该阶段可以提供类似于$setOnInsert更新运算符表达式的行为

  • $set阶段,该阶段可以提供类似于$set更新运算符表达式的行为

  • 聚合变量 NOW,其解析为当前日期和时间,可以提供类似于 $currentDate 更新运算符表达式的行为。

db.books.update(
{ item: "MRQ014", ratings: [2, 5, 3] }, // Query parameter
[ // Aggregation pipeline
{ $replaceRoot: { newRoot: { $mergeObjects: [ { stock: 0 }, "$$ROOT" ] } } },
{ $set: { avgRating: { $avg: "$ratings" }, tags: [ "fiction", "murder" ], lastModified: "$$NOW" } }
],
{ upsert: true } // Options
)

如果没有文档匹配 <查询> 参数,则操作将以下文档插入到 books 集合(你的 ObjectId 值将不同)

{
"_id" : ObjectId("5e2921e0b4c550aad59d1ba9"),
"stock" : 0,
"item" : "MRQ014",
"ratings" : [ 2, 5, 3 ],
"avgRating" : 3.3333333333333335,
"tags" : [ "fiction", "murder" ],
"lastModified" : ISODate("2020-01-23T04:32:32.951Z")
}

提示

另请参阅

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

mongosh,将以下文档插入到 books 集合

db.books.insertMany( [
{
_id: 5,
item: "RQM909",
stock: 18,
info: { publisher: "0000", pages: 170 },
reorder: true
},
{
_id: 6,
item: "EFG222",
stock: 15,
info: { publisher: "1111", pages: 72 },
reorder: true
}
] )

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

db.books.update(
{ stock: { $gte: 10 } }, // Query parameter
{ // Update document
$set: { reorder: false, tags: [ "literature", "translated" ] }
},
{ upsert: true, multi: true } // Options
)

操作更新所有匹配的文档,并导致以下结果

{
"_id" : 5,
"item" : "RQM909",
"stock" : 18,
"info" : { "publisher" : "0000", "pages" : 170 },
"reorder" : false,
"tags" : [ "literature", "translated" ]
}
{
"_id" : 6,
"item" : "EFG222",
"stock" : 15,
"info" : { "publisher" : "1111", "pages" : 72 },
"reorder" : false,
"tags" : [ "literature", "translated" ]
}

如果集合没有匹配的文档,则操作将使用来自 <查询><更新> 规范的字段插入单个文档。例如,考虑以下操作

db.books.update(
{ "info.publisher": "Self-Published" }, // Query parameter
{ // Update document
$set: { reorder: false, tags: [ "literature", "hardcover" ], stock: 25 }
},
{ upsert: true, multi: true } // Options
)

操作将以下文档插入到books集合中(您的ObjectId值将不同)

{
"_id" : ObjectId("5db337934f670d584b6ca8e0"),
"info" : { "publisher" : "Self-Published" },
"reorder" : false,
"stock" : 25,
"tags" : [ "literature", "hardcover" ]
}

当你使用 upsert: true 执行 update() 并且查询与现有文档不匹配时,如果查询使用点符号指定了 _id 字段的条件,MongoDB 将拒绝插入新文档。

此限制确保了嵌入在_id文档中的字段顺序定义良好,且不依赖于查询中指定的顺序。

如果您尝试以这种方式插入文档,MongoDB将引发错误。例如,考虑以下更新操作。由于更新操作指定了upsert:true,并且查询使用点符号指定了_id字段的条件,因此当构造要插入的文档时,更新将导致错误。

db.collection.update(
{ "_id.name": "Robert Frost", "_id.uid": 0 }, // Query parameter
{ $set:
{
"categories": [ "poet", "playwright" ] // Replacement document
}
},
{ upsert: true } // Options
)

该操作的WriteResult返回以下错误

WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 111,
"errmsg" : "field at '_id' must be exactly specified, field at sub-path '_id.name'found"
}
})

提示

另请参阅

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

考虑一个例子,其中不存在名为Andy的文档,并且多个客户端几乎同时发出以下命令

db.people.update(
{ name: "Andy" },
{ $inc: { score: 1 } },
{
upsert: true,
multi: true
}
)

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

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

  • 只有一个 update() 操作可以成功插入一个新文档。

  • 其他 update() 操作要么更新新插入的文档,要么因为唯一键冲突而失败。

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

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

    • 更新操作不是 updateManymultifalse

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

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

      • 相等谓词的逻辑AND。例如 { "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)不匹配。

提示

另请参阅

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

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

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

db.students.insertMany( [
{ "_id" : 1, "student" : "Skye", "points" : 75, "commentsSemester1" : "great at math", "commentsSemester2" : "loses temper", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 2, "students" : "Elizabeth", "points" : 60, "commentsSemester1" : "well behaved", "commentsSemester2" : "needs improvement", "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }
] )

假设不是分开的 commentsSemester1commentsSemester2 字段,而是将这些字段合并到新的 comments 字段中。以下更新操作使用聚合管道来

  • 添加新的 comments 字段并设置 lastUpdate 字段。

  • 从集合中的所有文档中删除 commentsSemester1commentsSemester2 字段。

db.members.update(
{ },
[
{ $set: { comments: [ "$commentsSemester1", "$commentsSemester2" ], lastUpdate: "$$NOW" } },
{ $unset: [ "commentsSemester1", "commentsSemester2" ] }
],
{ multi: true }
)

注意

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

第一阶段

$set 阶段

  • 创建一个新数组字段 comments,其元素是 commentsSemester1commentsSemester2 字段的当前内容

  • 将字段 lastUpdate 设置为聚合变量 NOW 的值。聚合变量 NOW 表示当前的日期时间值,并在整个管道中保持不变。要访问聚合变量,请在变量前加双美元符号 $$ 并用引号括起来。

第二阶段
$unset 阶段删除了 commentsSemester1commentsSemester2 字段。

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

{ "_id" : 1, "student" : "Skye", "status" : "Modified", "points" : 75, "lastUpdate" : ISODate("2020-01-23T05:11:45.784Z"), "comments" : [ "great at math", "loses temper" ] }
{ "_id" : 2, "student" : "Elizabeth", "status" : "Modified", "points" : 60, "lastUpdate" : ISODate("2020-01-23T05:11:45.784Z"), "comments" : [ "well behaved", "needs improvement" ] }

提示

另请参阅

创建包含以下文档的 students3 集合

db.students3.insertMany( [
{ "_id" : 1, "tests" : [ 95, 92, 90 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 2, "tests" : [ 94, 88, 90 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") },
{ "_id" : 3, "tests" : [ 70, 75, 82 ], "lastUpdate" : ISODate("2019-01-01T00:00:00Z") }
] )

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

db.students3.update(
{ },
[
{ $set: { average : { $trunc: [ { $avg: "$tests" }, 0 ] }, lastUpdate: "$$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"
} } } }
],
{ multi: true }
)

注意

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

第一阶段

$set 阶段

  • 根据 tests 字段的平均值计算一个新字段 average。有关 $avg 聚合运算符的更多信息,请参阅 $avg,有关 $trunc 截断聚合运算符的更多信息,请参阅 $trunc

  • 将字段 lastUpdate 设置为聚合变量 NOW 的值。聚合变量 NOW 表示当前的日期时间值,并在整个管道中保持不变。要访问聚合变量,请在变量前加双美元符号 $$ 并用引号括起来。

第二阶段
$set 阶段根据前一阶段计算出的 average 字段计算一个新字段 grade。有关 $switch 聚合运算符的更多信息,请参阅 $switch

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

{ "_id" : 1, "tests" : [ 95, 92, 90 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 92, "grade" : "A" }
{ "_id" : 2, "tests" : [ 94, 88, 90 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 90, "grade" : "A" }
{ "_id" : 3, "tests" : [ 70, 75, 82 ], "lastUpdate" : ISODate("2020-01-24T17:29:35.340Z"), "average" : 75, "grade" : "C" }

提示

另请参阅

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

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

您可以在更新文档中多次包含相同的标识符;但是,对于更新文档中的每个不同的标识符 ($[identifier]),您必须指定一个相应的数组过滤文档。也就是说,您不能为相同的标识符指定多个数组过滤文档。例如,如果更新语句包括标识符 x(可能多次),您不能为包含 2 个单独过滤文档的 x 指定以下 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 } }
]

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

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

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

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

要更新数组中所有大于或等于 100 的元素,请使用带有 arrayFilters 选项的过滤位置运算符 $[<identifier>]

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

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

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

您还可以使用 arrayFilters 参数来更新文档数组中特定字段的值。

mongosh 中,创建一个名为 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.students2.update(
{ },
{ $set: { "grades.$[elem].mean" : 100 } },
{
multi: true,
arrayFilters: [ { "elem.grade": { $gte: 85 } } ]
}
)

操作完成后,集合中的文档如下

{
"_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 }
]
}

mongosh 中,创建一个包含以下文档的 newStudents 集合

db.newStudents.insertMany( [
{ "_id" : 1, "student" : "Richard", "grade" : "F", "points" : 0, "comments1" : null, "comments2" : null },
{ "_id" : 2, "student" : "Jane", "grade" : "A", "points" : 60, "comments1" : "well behaved", "comments2" : "fantastic student" },
{ "_id" : 3, "student" : "Ronan", "grade" : "F", "points" : 0, "comments1" : null, "comments2" : null },
{ "_id" : 4, "student" : "Noah", "grade" : "D", "points" : 20, "comments1" : "needs improvement", "comments2" : null },
{ "_id" : 5, "student" : "Adam", "grade" : "F", "points" : 0, "comments1" : null, "comments2" : null },
{ "_id" : 6, "student" : "Henry", "grade" : "A", "points" : 86, "comments1" : "fantastic student", "comments2" : "well behaved" }
] )

在集合上创建以下索引

db.newStudents.createIndex( { grade: 1 } )

以下更新操作显式 提示 使用索引 {grade: 1 }

db.newStudents.update(
{ points: { $lte: 20 }, grade: "F" }, // Query parameter
{ $set: { comments1: "failed class" } }, // Update document
{ multi: true, hint: { grade: 1 } } // Options
)

注意

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

更新命令返回以下内容

WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })

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

db.newStudents.explain().update(
{ "points": { $lte: 20 }, "grade": "F" },
{ $set: { "comments1": "failed class" } },
{ multi: true, hint: { grade: 1 } }
)

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

版本5.0.

要定义可以在命令的其他地方访问的变量,请使用 let 选项。

注意

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

创建集合 cakeFlavors

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

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

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

以下对副本集的操作指定了写入关注为 w: 2,写入超时为 5000 毫秒。此操作会在写入传播到主节点和一个副节点后返回,或者超时 5 秒后返回。

db.books.update(
{ stock: { $lte: 10 } },
{ $set: { reorder: true } },
{
multi: true,
writeConcern: { w: 2, wtimeout: 5000 }
}
)

指定操作要使用的 排序规则

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

排序选项的语法如下

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

在指定排序时,locale字段是必需的;所有其他排序字段都是可选的。有关字段的描述,请参阅排序文档。

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

如果未为集合或操作指定排序,MongoDB将使用先前版本中用于字符串比较的简单二进制比较。

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

mongosh中,创建一个名为myColl的集合,包含以下文档

db.myColl.insertMany( [
{ _id: 1, category: "café", status: "A" },
{ _id: 2, category: "cafe", status: "a" },
{ _id: 3, category: "cafE", status: "a" }
] )

以下操作包含排序选项,并将multi设置为true以更新所有匹配的文档

db.myColl.update(
{ category: "cafe" },
{ $set: { status: "Updated" } },
{
collation: { locale: "fr", strength: 1 },
multi: true
}
)

该操作写入结果返回以下文档,表明集合中的三个文档都已更新

WriteResult({ "nMatched" : 3, "nUpserted" : 0, "nModified" : 3 })

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

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

db.collection.update()方法返回一个包含操作状态的WriteResult()对象。在成功的情况下,该WriteResult()对象包含匹配查询条件的文档数、通过更新插入的文档数以及修改的文档数

WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

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

WriteResult({
"nMatched" : 1,
"nUpserted" : 0,
"nModified" : 1,
"writeConcernError": {
"code" : 64,
"errmsg" : "waiting for replication timed out",
"errInfo" : {
"wtimeout" : true,
"writeConcern" : {
"w" : "majority",
"wtimeout" : 100,
"provenance" : "getLastErrorDefaults"
}
}
})

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

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

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

WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" : {
"code" : 7,
"errmsg" : "could not contact primary for replica set shard-a"
}
})

返回

db.collection.unhideIndex

© . This site is unofficial and not affiliated with MongoDB, Inc.