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

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

带驱动程序的 MongoDB

本页面文档 mongosh 方法。要查看 MongoDB 驱动程序中的等效方法,请参阅您的编程语言的相应页面:
db.collection.updateOne(filter, update, options)

根据筛选器更新集合内的单个文档。

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

  • MongoDB Atlas: The fully managed service for MongoDB deployments in the cloud

注意

This command is supported in all MongoDB Atlas clusters. For information on Atlas support for all commands, see Unsupported Commands.

updateOne()方法采用以下语法:

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

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

Parameter
类型
说明

文档

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

指定空文档 { } 以更新集合中返回的第一个文档。

文档或管道

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

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

upsert

布尔

Optional. When true, updateOne() 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.

let

文档

可选。

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

文档语法为:

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

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

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

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

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

sort

文档

可选。

如果查询选择了多个文档,则确定该操作更新了哪个文档。updateOne 按此参数指定的排序顺序更新第一个文档。

如果 sort 参数不是文档,则操作错误。

MongoDB 不按特定顺序将文档存储在集合中。对包含重复值的字段进行排序时,可能会以任何顺序返回包含这些值的文档。

$sort 操作不是“稳定排序”,这意味着具有等效排序键的文档在输出中不一定能保持与输入相同的相对顺序。

如果排序条件中指定的字段在两个文档中都不存在,那么它们排序所依据的值是相同的。这两个文档可以以任何顺序返回。

如果需要一致的排序顺序,请在排序中至少纳入一个包含唯一值的字段。最简单方法是在排序查询中纳入 _id 字段。

有关更多信息,请参阅排序一致性。

8.0版本新增。

整型

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

布尔

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

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

  • matchedCount 包含匹配文档的数量

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

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

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

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

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

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

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

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

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

db.collection.updateOne() finds the first document that matches the filter and applies the specified update modifications.

For the update specifications, the db.collection.updateOne() method can accept a document that only contains update operator expressions.

例如:

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

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

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

例如:

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

注意

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

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

For examples, see Update with Aggregation Pipeline.

  • 从MongoDB 8.0开始,如果您在分分片的集合上指定upsert: true ,则无需在过滤中包含完整的分分片键。

  • If upsert: true and no documents match the filter, db.collection.updateOne() creates a new document based on the filter criteria and update modifications. See Update with Upsert.

  • For additional db.collection.updateOne() behavior on a sharded collection, see Sharded Collections.

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

要在分片集合上使用 db.collection.updateOne():

  • 从MongoDB 8.0开始,如果您在分分片的集合上指定upsert: true ,则无需在过滤中包含完整的分分片键。

  • If you don't specify upsert: true, you must include an exact match on the _id field or target a single shard (such as by including the shard key in the filter).

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

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

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

警告

分片集合中的文档可能缺少分片键字段。采取预防措施,避免在更改文档的分片键值时意外删除分片键。

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

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

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

  • You must include an equality filter on the full shard key.

See also upsert on a Sharded Collection.

  • 从版本 7.1 开始,您不需要在查询规范中提供分片键 或 _id 字段。

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

    此外,以下要求也适用:

    任务
    要求

    若要设为 null

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

    要设置为非 null 值

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

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

    提示

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

另请参阅:

updateOne() 与db.collection.explain() 不兼容。

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

重要

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

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

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

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

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

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

restaurant 集合包含以下文档:

db.restaurant.insertMany( [
{ _id: 1, name: "Central Perk Cafe", Borough: "Manhattan" },
{ _id: 2, name: "Rock A Feller Bar and Grill", Borough: "Queens", violations: 2 },
{ _id: 3, name: "Empire State Pub", Borough: "Brooklyn", violations: 0 }
] )

如下操作将在 name 为 Central Perk Cafe 的文档上设置 violations 字段:

try {
db.restaurant.updateOne(
{ "name" : "Central Perk Cafe" },
{ $set: { "violations" : 3 } }
);
} catch (e) {
print(e);
}

该操作返回:

{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

如果未找到匹配项,那么操作将返回:

{ "acknowledged" : true, "matchedCount" : 0, "modifiedCount" : 0 }

Setting upsert: true would insert the document if no match was found. See Update with Upsert

db.collection.updateOne() 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.

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

使用以下文档创建 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, student: "Elizabeth", points: 60, commentsSemester1: "well behaved", commentsSemester2: "needs improvement", lastUpdate: ISODate("2019-01-01T00:00:00Z") }
] )

假设希望像第二份文档一样,将第一份文档中的 commentsSemester1 和 commentsSemester2 字段聚集到一个 comments 字段中,而不单独使用这两个字段。以下更新操作使用聚合管道:

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

  • 删除集合中所有文档的 commentsSemester1 和 commentsSemester2 字段。

确保更新命令中的筛选器定针对唯一文档。以下代码中的字段 id 便是此类筛选器的示例:

db.students.updateOne(
{ _id: 1 },
[
{ $set: { status: "Modified", comments: [ "$commentsSemester1", "$commentsSemester2" ], lastUpdate: "$$NOW" } },
{ $unset: [ "commentsSemester1", "commentsSemester2" ] }
]
)

注意

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

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

第一个阶段:

$set 阶段:

  • 创建一个新的数组字段 comments,其元素是 commentsSemester1 和 commentsSemester2 字段的当前内容,并且

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

第二阶段
$unset 阶段删除 commentsSemester1 和 commentsSemester2 字段。

执行该命令之后,集合中将包含以下文档:

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

聚合管道允许更新根据当前字段值执行条件更新,并使用当前字段值计算单独的字段值。

例如,使用以下文档创建 students3 集合:

db.students3.insertMany( [
{ _id: 1, tests: [ 95, 92, 90 ], average: 92, grade: "A", lastUpdate: ISODate("2020-01-23T05:18:40.013Z") },
{ _id: 2, tests: [ 94, 88, 90 ], average: 91, grade: "A", lastUpdate: ISODate("2020-01-23T05:18:40.013Z") },
{ _id: 3, tests: [ 70, 75, 82 ], lastUpdate: ISODate("2019-01-01T00:00:00Z") }
] )

第三个文档 _id: 3 缺少 average 和 grade 字段。使用聚合管道,可以根据计算出的平均成绩和字母等级来更新文档。

db.students3.updateOne(
{ _id: 3 },
[
{ $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"
} } } }
]
)

注意

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

第一个阶段:

$set 阶段:

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

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

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

执行该命令之后,集合中将包含以下文档:

{ _id: 1, tests: [ 95, 92, 90 ], average: 92, grade: "A", lastUpdate: ISODate("2020-01-23T05:18:40.013Z") }
{ _id: 2, tests: [ 94, 88, 90 ], average: 91, grade: "A", lastUpdate: ISODate("2020-01-23T05:18:40.013Z") }
{ _id: 3, tests: [ 70, 75, 82 ], lastUpdate: ISODate("2020-01-24T17:33:30.674Z"), average: 75, grade: "C" }

restaurant 集合包含以下文档:

db.restaurant.insertMany( [
{ _id: 1, name: "Central Perk Cafe", Borough: "Manhattan", violations: 3 },
{ _id: 2, name: "Rock A Feller Bar and Grill", Borough: "Queens", violations: 2 },
{ _id: 3, name: "Empire State Pub", Borough: "Brooklyn", violations: "0" }
] )

以下操作尝试使用 name : "Pizza Rat's Pizzaria" 更新文档,同时 upsert: true:

try {
db.restaurant.updateOne(
{ "name" : "Pizza Rat's Pizzaria" },
{ $set: {"_id" : 4, "violations" : 7, "borough" : "Manhattan" } },
{ upsert: true }
);
} catch (e) {
print(e);
}

因为 upsert:true,所以该文档是基于 filter 和 update 标准 inserted 的。该操作返回:

{
"acknowledged" : true,
"matchedCount" : 0,
"modifiedCount" : 0,
"upsertedId" : 4,
"upsertedCount": 1
}

该集合现在包含以下文档:

{ _id: 1, name: "Central Perk Cafe", Borough: "Manhattan", violations: 3 },
{ _id: 2, name: "Rock A Feller Bar and Grill", Borough: "Queens", violations: 2 },
{ _id: 3, name: "Empire State Pub", Borough: "Brooklyn", violations: 4 },
{ _id: 4, name: "Pizza Rat's Pizzaria", Borough: "Manhattan", violations: 7 }

name 字段使用 filter 条件填充,而 update 操作符用于创建文档的其余部分。

以下操作会使用大于 10 的 violations 更新第一个文档:

try {
db.restaurant.updateOne(
{ "violations" : { $gt: 10} },
{ $set: { "Closed" : true } },
{ upsert: true }
);
} catch (e) {
print(e);
}

该操作返回:

{
"acknowledged" : true,
"matchedCount" : 0,
"modifiedCount" : 0,
"upsertedId" : ObjectId("56310c3c0c5cbb6031cafaea")
}

该集合现在包含以下文档:

{ _id: 1, name: "Central Perk Cafe", Borough: "Manhattan", violations: 3 },
{ _id: 2, name: "Rock A Feller Bar and Grill", Borough: "Queens", violations: 2 },
{ _id: 3, name: "Empire State Pub", Borough: "Brooklyn", violations: 4 },
{ _id: 4, name: "Pizza Rat's Pizzaria", Borough: "Manhattan", violations: 7 }
{ _id: ObjectId("56310c3c0c5cbb6031cafaea"), Closed: true }

由于没有文档与过滤器匹配,并且 upsert 是 true,因此 updateOne 仅使用生成的 _id 和 update 标准插入文档。

给定一个三节点副本集,以下操作指定 w 为 majority,指定 wtimeout 为 100:

try {
db.restaurant.updateOne(
{ "name" : "Pizza Rat's Pizzaria" },
{ $inc: { "violations" : 3}, $set: { "Closed" : true } },
{ w: "majority", wtimeout: 100 }
);
} catch (e) {
print(e);
}

如果主节点和至少一个从节点在 100 毫秒内确认每个写入操作,则返回:

{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

如果确认花费的时间超过wtimeout限制,则会引发以下异常:

WriteConcernError({
"code" : 64,
"errmsg" : "waiting for replication timed out",
"errInfo" : {
"wtimeout" : true,
"writeConcern" : {
"w" : "majority",
"wtimeout" : 100,
"provenance" : "getLastErrorDefaults"
}
}
})

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

来源
说明

clientSupplied

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

customDefault

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

getLastErrorDefaults

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

implicitDefault

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

8.0版本新增。

以下示例将停用评分最低的活跃用户:

db.people.updateOne(
{ state: "active" },
{ $set: { state: "inactive" } },
{ sort: { rating: 1 } }
)

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

集合 myColl 包含以下文档:

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

以下操作包括排序规则选项:

db.myColl.updateOne(
{ category: "cafe" },
{ $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 的所有元素,请在 db.collection.updateOne 方法中使用带有 arrayFilters 选项的过滤器位置操作符 $[<identifier>]:

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

该操作更新单个文档的 grades 字段,操作后,该集合包含以下文档:

{ _id: 1, grades: [ 95, 92, 90 ] }
{ _id: 2, grades: [ 98, 100, 100 ] }
{ _id: 3, grades: [ 95, 110, 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 字段的值,请将 过滤器 位置操作符 $[<identifier>] 与 db.collection.updateOne 方法中的 arrayFilters 结合使用:

db.students2.updateOne(
{ },
{ $set: { "grades.$[elem].mean" : 100 } },
{ 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: 75, std: 6 },
{ grade: 87, mean: 90, std: 3 },
{ grade: 85, mean: 85, std: 4 }
]
}

使用以下文档创建示例 students 集合:

db.students.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.students.createIndex( { grade: 1 } )
db.students.createIndex( { points: 1 } )

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

注意

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

db.students.updateOne(
{ "points": { $lte: 20 }, "grade": "F" },
{ $set: { "comments1": "failed class" } },
{ hint: { grade: 1 } }
)

更新命令返回以下内容:

{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

注意

即使 3 个文档符合更新条件,updateOne 仅修改其查找到的第一个文档。因此,即使学生 Richard、Ronan 和 Adam 都符合条件,但只更新 Richard。

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

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

在版本8.1.2中进行了更改。

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

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

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

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

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

该示例创建这些用户:

  • James 角色为 Billing。

  • Michelle 角色为 Provider。

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

1

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

运行:

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

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

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"
}
] )

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

1

运行:

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

运行:

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

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

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

1

运行:

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

运行:

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

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

提示

要更新多个文档,请参阅 db.collection.updateMany()。