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

db. 集合.bulkWrite()(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.bulkWrite()

执行多个写操作,并控制执行顺序。

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

  • 每个写入操作的计数。

  • 一个数组:为每份成功插入或更新的文档一个 _id

db.collection.bulkWrite() 在以下环境中托管的部署中可用:

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

注意

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

注意

You can't perform bulk write operations in the Atlas UI. To insert multiple documents, you must insert an array of documents. To learn more, see Create, View, Update, and Delete Documents in the Atlas documentation.

The bulkWrite() method has the following form:

db.collection.bulkWrite(
[ <operation 1>, <operation 2>, ... ],
{
writeConcern : <document>,
ordered : <boolean>
}
)

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

Parameter
类型
说明

operations

阵列

一个包含 bulkWrite()写入操作的数组。

有效操作包括:

请参阅写操作,了解每种操作的用法

writeConcern

文档

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

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

ordered

布尔

可选。布尔值,指定操作是串行执行(true,默认)还是可以按任意顺序执行(false)。当为 true 时,在出现第一个错误时停止;为 false 时,继续处理剩余操作。

bulkWrite() 获取一系列写入操作并执行每个写入操作。默认情况下,操作按顺序执行。有关控制写入操作执行顺序的信息,请参见执行操作

将单个文档插入集合中。

db.collection.bulkWrite( [
{ insertOne : { "document" : <document> } }
] )

updateOne 更新集合中与过滤器匹配的单个文档。如果存在多个匹配的文档,updateOne 将只更新第一个匹配的文档。

db.collection.bulkWrite( [
{ updateOne :
{
"filter": <document>,
"update": <document or pipeline>,
"upsert": <boolean>,
"collation": <document>,
"arrayFilters": [ <filterdocument1>, ... ],
"hint": <document|string>
}
}
] )

updateMany 更新集合中与过滤器匹配的所有文档。

db.collection.bulkWrite( [
{ updateMany :
{
"filter" : <document>,
"update" : <document or pipeline>,
"upsert" : <boolean>,
"collation": <document>,
"arrayFilters": [ <filterdocument1>, ... ],
"hint": <document|string>
}
}
] )
字段
注意

filter

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

update

要执行的更新操作。可以指定以下任一项:

upsert

可选。一个布尔值,表明是否执行更新插入操作。

默认情况下,upsertfalse

arrayFilters

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

collation

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

hint

可选。用于支持更新filter索引。如果指定不存在的索引,则操作出错。

replaceOne 将替换集合中与筛选器匹配的单个文档。如果存在多个匹配的文档,replaceOne 将只替换第一个匹配的文档。

db.collection.bulkWrite([
{ replaceOne :
{
"filter" : <document>,
"replacement" : <document>,
"upsert" : <boolean>,
"collation": <document>,
"hint": <document|string>
}
}
] )
字段
注意

filter

替换操作的选择条件。可以使用与 db.collection.find() 方法中相同的查询选择器

replacement

替换文档。文档不能包含更新操作符

upsert

可选。一个布尔值,表明是否执行更新插入操作。默认情况下,upsertfalse

collation

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

hint

可选。用于支持更新filter索引。如果指定不存在的索引,则操作出错。

deleteOne 删除集合中与过滤器匹配的单个文档。如果存在多个匹配的文档,deleteOne 将只删除第一个匹配的文档。

db.collection.bulkWrite([
{ deleteOne : {
"filter" : <document>,
"collation" : <document> // Available starting in 3.4
} }
] )

deleteMany 删除集合中与过滤器匹配的所有文档。

db.collection.bulkWrite([
{ deleteMany: {
"filter" : <document>,
"collation" : <document> // Available starting in 3.4
} }
] )
字段
注意

filter

删除操作的选择条件。可以使用与 db.collection.find() 方法中相同的查询选择器

collation

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

如果文档未指定 _id 字段,则 mongod 会添加 _id 字段,并在插入或更新该文档之前为其分配唯一的 ObjectId() 字段。多数驱动程序都会创建一个 ObjectId 并插入 _id 字段,但如果驱动程序或应用程序不这样做,则 mongod 将创建并填充 _id

如果文档包含 _id 字段,则 _id 值在集合中必须是唯一的,以避免重复键错误。

更新或替换操作不能指定与原始文档不同的 _id 值。

ordered 参数控制操作是串行执行还是以任意顺序执行。

使用 ordered : true(默认)时,操作会串行执行。如果发生错误,则不会执行后续操作。

使用 ordered : false,操作可以并行执行。即使某些操作失败,所有没有错误的操作也会完成。

每组中的操作次数不得超过数据库的 maxWriteBatchSize 值。maxWriteBatchSize 的默认值为 100,000。该值会显示在 hello.maxWriteBatchSize 字段中。

此限制可防止错误消息过大的问题。如果一个群组超过此限制,则客户端驱动程序会将该群组分成计数小于或等于限制值的更小群组。例如,对于 maxWriteBatchSize 值为 100,000 的情况,如果队列由 200,000 个操作组成,则驱动程序将创建 2 个群组,每个群组包含 100,000 个操作。

注意

该驱动程序仅在使用高级 API 时会将上述群组划分为多个更小的群组。如果直接使用 db.runCommand()(例如,在编写驱动程序时),MongoDB 在尝试执行超过限制的写入批处理时会引发错误。

如果单个批处理的错误报告变得过大,MongoDB 会将所有剩余的错误消息截断为空字符串。如果至少存在两条总大小大于 1MB 的错误消息,则会将其截断。

大小和分组机制是内部性能细节,在未来版本中可能会有变化。

在分片集合上执行操作的 ordered 列表通常比执行 unordered 列表慢,因为对于有序列表,每个操作都必须等待前一个操作完成。

bulkWrite()固定大小集合有限制:

  • updateOneupdateMany 会在更新增加文档大小时抛出 WriteError

  • replaceOne 如果替换文档大于原始文档,则会抛出 WriteError

  • deleteOnedeleteMany 对固定大小集合抛出 WriteError

bulkWrite() 会在出现错误时引发 BulkWriteError 异常。请参阅事务中的错误处理。

当排除了写关注错误时,有序操作将在发生错误之后停止,而无序操作会继续处理队列中的任何剩余写操作(除非在事务内运行)。请参阅事务中的错误处理。

写关注错误显示在 writeConcernErrors 字段中,所有其他错误显示在 writeErrors 字段中。如果遇到错误,将显示成功的写入操作的数量,而不是插入的 _id 值。有序操作会显示遇到的单个错误,而无序操作会显示数组中的每个错误。

如果您的集合使用模式验证并将validationAction设立为error ,则插入无效文档或使用无效值更新文档会引发错误。 执行operations大量中无效操作之前的操作并将其写入集合。 ordered字段决定是否执行剩余操作。

bulkWrite() 可用于分布式事务。

重要

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

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

对于特征兼容性版本 (fcv) "4.4" 及更高版本,如果在事务中对不存在的集合执行了插入操作或更新操作 (upsert: true),则会隐式创建该集合。

注意

您无法在跨分片写事务中创建新集合。例如,如果您在一个分片中写入一个现有集合,并在另一个分片中隐式创建一个集合,MongoDB 将无法在同一事务中执行这两个操作。

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

从MongoDB4.2 开始,如果db.collection.bulkWrite() 操作在ACID 事务内部遇到错误,该方法会引发 BulkWriteException(与ACID 事务外部相同)。

在 4.0 中,如果 bulkWrite 操作在事务内遇到错误,则引发的错误不会包装为 BulkWriteException

在事务内部,批量写入中的第一个错误会导致整个批量写入失败并中止事务,即使批量写入是无序的也是如此。

了解 bulkWrite() 操作排序和错误处理非常重要。默认下,bulkWrite() 运行一个有序的操作列表:

  • 操作以串行方式执行。

  • 如果某个操作出错,将不会执行此操作以及任何后续操作。

  • 在错误操作完成之前列出的操作。

bulkWrite() 示例使用 pizzas集合:

db.pizzas.insertMany( [
{ _id: 0, type: "pepperoni", size: "small", price: 4 },
{ _id: 1, type: "cheese", size: "medium", price: 7 },
{ _id: 2, type: "vegan", size: "large", price: 8 }
] )

The following bulkWrite() example runs these operations on the pizzas collection:

  • 使用 insertOne 添加两个文档。

  • 使用 updateOne 更新一个文档。

  • 使用 deleteOne 删除文档。

  • 使用 replaceOne 替换一个文档。

try {
db.pizzas.bulkWrite( [
{ insertOne: { document: { _id: 3, type: "beef", size: "medium", price: 6 } } },
{ insertOne: { document: { _id: 4, type: "sausage", size: "large", price: 10 } } },
{ updateOne: {
filter: { type: "cheese" },
update: { $set: { price: 8 } }
} },
{ deleteOne: { filter: { type: "pepperoni"} } },
{ replaceOne: {
filter: { type: "vegan" },
replacement: { type: "tofu", size: "small", price: 4 }
} }
] )
} catch( error ) {
print( error )
}

输出示例,包括已完成操作的摘要:

{
acknowledged: true,
insertedCount: 2,
insertedIds: { '0': 3, '1': 4 },
matchedCount: 2,
modifiedCount: 2,
deletedCount: 1,
upsertedCount: 0,
upsertedIds: {}
}

如果在运行前面的 bulkWrite()示例之前,该集合已包含 _id4 的文档,则会为第二个 insertOne 操作返回以下重复键异常:

writeErrors: [
WriteError {
err: {
index: 1,
code: 11000,
errmsg: 'E11000 duplicate key error collection: test.pizzas index: _id_ dup key: { _id: 4 }',
op: { _id: 4, type: 'sausage', size: 'large', price: 10 }
}
}
],
result: BulkWriteResult {
result: {
ok: 1,
writeErrors: [
WriteError {
err: {
index: 1,
code: 11000,
errmsg: 'E11000 duplicate key error collection: test.pizzas index: _id_ dup key: { _id: 4 }',
op: { _id: 4, type: 'sausage', size: 'large', price: 10 }
}
}
],
writeConcernErrors: [],
insertedIds: [ { index: 0, _id: 3 }, { index: 1, _id: 4 } ],
nInserted: 1,
nUpserted: 0,
nMatched: 0,
nModified: 0,
nRemoved: 0,
upserted: []
}
}

由于 bulkWrite()示例是有序的,因此仅完成第一个 insertOne 操作。

要完成没有错误的所有操作,运行bulkWrite() 并将 ordered设立为 false。有关示例,请参阅以下部分。

要指定无序 bulkWrite(),请将 ordered设立为 false

在无序列表的 bulkWrite() 操作列表中:

  • 操作可以并行运行(不保证)。有关详细信息,请参阅有序操作和无序操作

  • 出现错误的操作未完成。

  • 所有无错误的操作都已完成。

继续 pizzas 集合示例,删除并重新创建此集合:

db.pizzas.insertMany( [
{ _id: 0, type: "pepperoni", size: "small", price: 4 },
{ _id: 1, type: "cheese", size: "medium", price: 7 },
{ _id: 2, type: "vegan", size: "large", price: 8 }
] )

在以下示例中:

  • bulkWrite()pizzas集合运行无序操作。

  • 第二个 insertOne 操作具有与第一个 insertOne 相同的 _id,这样会产生一个重复键错误。

try {
db.pizzas.bulkWrite( [
{ insertOne: { document: { _id: 3, type: "beef", size: "medium", price: 6 } } },
{ insertOne: { document: { _id: 3, type: "sausage", size: "large", price: 10 } } },
{ updateOne: {
filter: { type: "cheese" },
update: { $set: { price: 8 } }
} },
{ deleteOne: { filter: { type: "pepperoni"} } },
{ replaceOne: {
filter: { type: "vegan" },
replacement: { type: "tofu", size: "small", price: 4 }
} }
],
{ ordered: false } )
} catch( error ) {
print( error )
}

输出示例,包括重复键错误和已完成操作的摘要:

writeErrors: [
WriteError {
err: {
index: 1,
code: 11000,
errmsg: 'E11000 duplicate key error collection: test.pizzas index: _id_ dup key: { _id: 3 }',
op: { _id: 3, type: 'sausage', size: 'large', price: 10 }
}
}
],
result: BulkWriteResult {
result: {
ok: 1,
writeErrors: [
WriteError {
err: {
index: 1,
code: 11000,
errmsg: 'E11000 duplicate key error collection: test.pizzas index: _id_ dup key: { _id: 3 }',
op: { _id: 3, type: 'sausage', size: 'large', price: 10 }
}
}
],
writeConcernErrors: [],
insertedIds: [ { index: 0, _id: 3 }, { index: 1, _id: 3 } ],
nInserted: 1,
nUpserted: 0,
nMatched: 2,
nModified: 2,
nRemoved: 1,
upserted: []
}
}

由于重复键错误,第二个 insertOne 操作失败。在无序 bulkWrite() 中,任何没有错误的操作都已完成。

在版本8.1.2中进行了更改。

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

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

继续 pizzas 集合示例,删除并重新创建此集合:

db.pizzas.insertMany( [
{ _id: 0, type: "pepperoni", size: "small", price: 4 },
{ _id: 1, type: "cheese", size: "medium", price: 7 },
{ _id: 2, type: "vegan", size: "large", price: 8 }
] )

以下 bulkWrite() 示例对 pizzas 集合运行操作,并设置 "majority" 写关注(write concern) 和 100 毫秒超时:

try {
db.pizzas.bulkWrite( [
{ updateMany: {
filter: { size: "medium" },
update: { $inc: { price: 0.1 } }
} },
{ updateMany: {
filter: { size: "small" },
update: { $inc: { price: -0.25 } }
} },
{ deleteMany: { filter: { size: "large" } } },
{ insertOne: {
document: { _id: 4, type: "sausage", size: "small", price: 12 }
} } ],
{ writeConcern: { w: "majority", wtimeout: 100 } }
)
} catch( error ) {
print( error )
}

如果大多数副本集成员确认操作的时间超过 wtimeout,则该示例返回写关注错误和已完成操作的摘要:

result: BulkWriteResult {
result: {
ok: 1,
writeErrors: [],
writeConcernErrors: [
WriteConcernError {
err: {
code: 64,
codeName: 'WriteConcernTimeout',
errmsg: 'waiting for replication timed out',
errInfo: { wtimeout: true, writeConcern: [Object] }
}
}
],
insertedIds: [ { index: 3, _id: 4 } ],
nInserted: 0,
nUpserted: 0,
nMatched: 2,
nModified: 2,
nRemoved: 0,
upserted: [],
opTime: { ts: Timestamp({ t: 1660329086, i: 2 }), t: Long("1") }
}
}
给本页内容打分