db.collection.bulkWrite()

在本页面

定义

  • db.collection. bulkWrite ()

    • version 3.2 中的新内容。

使用 order 执行控件执行多个写操作。

bulkWrite()具有以下语法:

db.collection.bulkWrite(
       [ <operation 1>, <operation 2>, ... ],
       {
          writeConcern : <document>,
          ordered : <boolean>
       }
    )
参数类型描述

operations

array

bulkWrite()写操作的 array。 有效操作为: insertOne updateOne updateMany deleteOne deleteMany replaceOne 有关每个操作的使用情况,请参阅写操作。

writeConcern

document

可选的。表示写关注的文件。省略使用默认写入问题。

ordered

boolean

可选的。一个 boolean,指定mongod实例是否应执行有序或无序操作执行。默认为true。 参阅执行操作

返回值:

一个布尔值acknowledgedtrue好像该操作在运行时带有 写关注点,或者false禁用了写关注点。 每个写入操作的计数。 一个数组,其中包含_id每个成功插入或插入的文档的。

行为

bulkWrite()采用 array 写操作并执行每个操作。默认情况下,操作在 order 中执行。请参阅执行操作以控制写操作执行的 order。

写操作

insertOne

将单个文档插入集合中。

见db.collection.insertOne()。

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

updateOne 和 updateMany

更改 version 3.6:updateOneupdateMany操作添加了对arrayFilters参数的支持,该参数确定要在 array 字段中修改哪些元素。有关详细信息,请参阅db.collection.updateOne()和db.collection.updateMany()。

已更改 version 3.4:添加对整理的支持。有关详细信息,请参阅db.collection.updateOne()和db.collection.updateMany()

updateOne更新集合中与过滤器匹配的单个文档。如果多个文档 match,updateOne将仅更新第一个匹配的文档。见db.collection.updateOne()。

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

updateMany更新集合中匹配过滤器的所有文档。见db.collection.updateMany()。

db.collection.bulkWrite( [
       { updateMany :
          {
             "filter" : <document>,
             "update" : <document>,
             "upsert" : <boolean>,
             "collation": <document>,
             "arrayFilters": [ <filterdocument1>, ... ]
          }
       }
    ] )
字段描述

filter

更新的选择标准。提供与 方法中相同的查询选择器db.collection.find()

update

要执行的更新操作。可以指定: 仅包含更新运算符表达式的文档。 一个聚合管道 [ <stage1>, <stage2>, ... ],指定要执行的修改。

upsert

可选的。一个布尔值,指示是否执行upsert。 默认情况下upsertfalse

arrayFilters

可选的。筛选器文档数组,用于确定要对数组字段进行更新操作要修改的数组元素。

collation

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

hint

可选的。用于支持更新的索引filter。如果指定的索引不存在,则操作错误。 4.2.1版中的新功能。

有关详细信息,请参见db.collection.updateOne()db.collection.updateMany()

replaceOne

replaceOne替换与过滤器匹配的集合中的单个文档。如果多个文档 match,replaceOne将仅替换第一个匹配的文档。

db.collection.bulkWrite([
       { replaceOne :
          {
             "filter" : <document>,
             "replacement" : <document>,
             "upsert" : <boolean>
          }
       }
    ] )
字段描述

filter

替换操作的选择标准。提供与 方法中相同的 查询选择器db.collection.find()

replacement

替换文件。该文档不能包含 更新运算符。

upsert

可选的。一个布尔值,指示是否执行upsert。默认情况下upsertfalse

collation

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

hint

可选的。用于支持更新的索引filter。如果指定的索引不存在,则操作错误。 4.2.1版中的新功能。

有关详细信息,请参见db.collection.replaceOne()

deleteOne 和 deleteMany

deleteOne删除集合中的一个文件 match 过滤器。如果多个文档 match,deleteOne将仅删除第一个匹配的文档。见db.collection.deleteOne()

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

deleteMany删除集合中匹配过滤器的所有文档。见db.collection.deleteMany()。

db.collection.bulkWrite([
       { deleteMany :  { "filter" : <document> } }
    ] )
字段描述

filter

删除操作的选择标准。提供与 方法中相同的 查询选择器db.collection.find()

collation

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

有关详细信息,请参见db.collection.deleteOne()db.collection.deleteMany()

_id 字段

如果文档未指定_id字段,则mongod添加_id字段并在插入或插入文档之前为文档指定唯一的ObjectId。大多数驱动程序创建一个 ObjectId 并插入_id字段,但如果驱动程序或 application 没有,mongod将创建并填充_id

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

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

执行操作

ordered参数指定bulkWrite()是否将在 order 中执行操作。默认情况下,操作在 order 中执行。

以下 code 表示带有五个操作的bulkWrite()。

db.collection.bulkWrite(
       [
          { insertOne : <document> },
          { updateOne : <document> },
          { updateMany : <document> },
          { replaceOne : <document> },
          { deleteOne : <document> },
          { deleteMany : <document> }
       ]
    )

在默认的ordered : true state 中,每个操作都将在 order 中执行,从第一个操作insertOne到最后一个操作deleteMany

如果ordered设置为 false,则mongod可以重新排序操作以增加 performance。 Applications 不应该依赖于 order 操作执行。

以下 code 表示无序bulkWrite(),包含六个操作:

db.collection.bulkWrite(
       [
          { insertOne : <document> },
          { updateOne : <document> },
          { updateMany : <document> },
          { replaceOne : <document> },
          { deleteOne : <document> },
          { deleteMany : <document> }
       ],
       { ordered : false }
    )

使用ordered : false时,操作结果可能会有所不同。对于 example,deleteOnedeleteMany可能会删除更多或更少的文档,具体取决于insertOneupdateOneupdateManyreplaceOne操作之前或之后的 run。

每个 group 中的操作数不能超过数据库maxWriteBatchSize的 value。从 MongoDB 3.6 开始,这个 value 是100,000。此值显示在isMaster.maxWriteBatchSize字段中。

此限制可防止出现超大错误消息的问题。如果 group 超过此limit,则 client 驱动程序将 group 分成较小的组,其计数小于或等于限制的 value。例如,对于100,000maxWriteBatchSize value,如果队列包含200,000操作,则驱动程序将创建 2 个组,每个组具有100,000个操作。

注意

使用 high-level API 时,驱动程序仅将 group 分为较小的组。如果直接使用db.runCommand()(对于 example,在编写驱动程序时),MongoDB 在尝试执行超出限制的写入批处理时会抛出错误。

从 MongoDB 3.6 开始,一旦单个批处理的错误报告变得太大,MongoDB 会将所有剩余的错误消息截断为空的 string。目前,一旦至少有 2 个错误消息,总大小大于1MB,则开始。

尺寸和分组机械是内部性能细节,在将来的版本中可能会有所变化。

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

上限收藏

bulkWrite()写操作在上限集合上使用时有限制。

如果update条件增加了要修改的文档的大小,则updateOneupdateMany抛出WriteError

如果replacement文档的大小比原始文档大,则replaceOne抛出WriteError

如果在上限集合中使用deleteOnedeleteMany则抛出WriteError

错误处理

bulkWrite()会在错误上抛出BulkWriteError exception。

排除写关注错误,有序操作在发生错误后停止,而无序操作继续处理队列中任何剩余的写操作。

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

事务

db.collection.bulkWrite()可以在多文档事务中使用。

如果在事务中运行,则集合必须已经存在才能进行插入和操作。upsert: true

如果在事务中运行,请不要为操作明确设置写关注点。要对事务使用写关注,请参见 事务和写关注。

重要

在大多数情况下,与单文档写入相比,多文档事务产生的性能成本更高,并且多文档事务的可用性不应替代有效的架构设计。在许多情况下, 非规范化数据模型(嵌入式文档和数组)将继续是您的数据和用例的最佳选择。也就是说,在许多情况下,适当地对数据建模将最大程度地减少对多文档交易的需求。

有关其他事务使用方面的注意事项(例如运行时限制和操作日志大小限制),另请参见 生产注意事项。

事务里面的错误处理

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

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

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

例子

批量写操作

guidebook数据库中的characters集合包含以下文档:

{ "_id" : 1, "char" : "Brisbane", "class" : "monk", "lvl" : 4 },
{ "_id" : 2, "char" : "Eldon", "class" : "alchemist", "lvl" : 3 },
{ "_id" : 3, "char" : "Meldane", "class" : "ranger", "lvl" : 3 }

以下bulkWrite()对集合执行多个操作:

try {
       db.characters.bulkWrite([
          { insertOne: { "document": { "_id": 4, "char": "Dithras", "class": "barbarian", "lvl": 4 } } },
          { insertOne: { "document": { "_id": 5, "char": "Taeln", "class": "fighter", "lvl": 3 } } },
          { updateOne : {
             "filter" : { "char" : "Eldon" },
             "update" : { $set : { "status" : "Critical Injury" } }
          } },
          { deleteOne : { "filter" : { "char" : "Brisbane"} } },
          { replaceOne : {
             "filter" : { "char" : "Meldane" },
             "replacement" : { "char" : "Tanys", "class" : "oracle", "lvl": 4 }
          } }
       ]);
    } catch (e) {
       print(e);
    }

该操作返回以下内容:

{
       "acknowledged" : true,
       "deletedCount" : 1,
       "insertedCount" : 2,
       "matchedCount" : 2,
       "upsertedCount" : 0,
       "insertedIds" : {
          "0" : 4,
          "1" : 5
       },
       "upsertedIds" : {
          }
}

如果集合在执行批量写入之前包含带有"_id" : 5"的文档,则在执行批量写入时,将为第二个 insertOne 抛出以下重复的 key exception:

BulkWriteError({
       "writeErrors" : [
          {
             "index" : 1,
             "code" : 11000,
             "errmsg" : "E11000 duplicate key error collection: guidebook.characters index: _id_ dup key: { : 5.0 }",
             "op" : {
                "_id" : 5,
                "char" : "Taeln",
                "class" : "fighter",
                "lvl" : 3
             }
          }
       ],
       "writeConcernErrors" : [ ],
       "nInserted" : 1,
       "nUpserted" : 0,
       "nMatched" : 0,
       "nModified" : 0,
       "nRemoved" : 0,
       "upserted" : [ ]
    })

由于ordered默认为 true,因此只有第一个操作成功完成。 rest 未执行。 尽管出现错误,使用ordered : false运行bulkWrite()将允许剩余的操作完成。

无序批量写入

guidebook数据库中的characters集合包含以下文档:

{ "_id" : 1, "char" : "Brisbane", "class" : "monk", "lvl" : 4 },
{ "_id" : 2, "char" : "Eldon", "class" : "alchemist", "lvl" : 3 },
{ "_id" : 3, "char" : "Meldane", "class" : "ranger", "lvl" : 3 }

以下bulkWrite()对characters集合执行多个unordered操作。请注意,其中一个insertOne阶段具有重复的_id value:

try {
       db.characters.bulkWrite([
          { insertOne: { "document": { "_id": 4, "char": "Dithras", "class": "barbarian", "lvl": 4 } } },
          { insertOne: { "document": { "_id": 4, "char": "Taeln", "class": "fighter", "lvl": 3 } } },
          { updateOne : {
             "filter" : { "char" : "Eldon" },
             "update" : { $set : { "status" : "Critical Injury" } }
          } },
          { deleteOne : { "filter" : { "char" : "Brisbane"} } },
          { replaceOne : {
             "filter" : { "char" : "Meldane" },
             "replacement" : { "char" : "Tanys", "class" : "oracle", "lvl": 4 }
          } }
       ], { ordered : false } );
    } catch (e) {
       print(e);
    }

该操作返回以下内容:

BulkWriteError({
       "writeErrors" : [
          {
             "index" : 1,
             "code" : 11000,
             "errmsg" : "E11000 duplicate key error collection: guidebook.characters index: _id_ dup key: { : 4.0 }",
             "op" : {
                "_id" : 4,
                "char" : "Taeln",
                "class" : "fighter",
                "lvl" : 3
             }
          }
       ],
       "writeConcernErrors" : [ ],
       "nInserted" : 1,
       "nUpserted" : 0,
       "nMatched" : 2,
       "nModified" : 2,
       "nRemoved" : 1,
       "upserted" : [ ]
    })

由于这是unordered操作,因此尽管存在 exception,仍会处理队列中剩余的写入。

批量写与写关注

enemies集合包含以下文档:

{ "_id" : 1, "char" : "goblin", "rating" : 1, "encounter" : 0.24 },
{ "_id" : 2, "char" : "hobgoblin", "rating" : 1.5, "encounter" : 0.30 },
{ "_id" : 3, "char" : "ogre", "rating" : 3, "encounter" : 0.2 },
{ "_id" : 4, "char" : "ogre berserker" , "rating" : 3.5, "encounter" : 0.12}

以下bulkWrite()使用100 毫秒写入关注值"majority"和超时值为对集合执行多个操作:

try {
       db.enemies.bulkWrite(
          [
             { updateMany :
                {
                   "filter" : { "rating" : { $gte : 3} },
                   "update" : { $inc : { "encounter" : 0.1 } }
                },
         },
         { updateMany :
            {
               "filter" : { "rating" : { $lt : 2} },
               "update" : { $inc : { "encounter" : -0.25 } }
            },
         },
         { deleteMany : { "filter" : { "encounter": { $lt : 0 } } } },
         { insertOne :
            {
               "document" :
                  {
                     "_id" :5, "char" : "ogrekin" , "rating" : 2, "encounter" : 0.31
                  }
            }
         }
      ],
      { writeConcern : { w : "majority", wtimeout : 100 } }
   );
} catch (e) {
   print(e);
}

如果副本集中所有必需节点确认写入操作所需的总 time 大于wtimeout,则在wtimeout期间过后将显示以下writeConcernError

BulkWriteError({
       "writeErrors" : [ ],
       "writeConcernErrors" : [
          {
             "code" : 64,
             "codeName" : "WriteConcernFailed",
             "errInfo" : {
                "wtimeout" : true
             },
             "errmsg" : "waiting for replication timed out"
          },
          {
             "code" : 64,
             "codeName" : "WriteConcernFailed",
             "errInfo" : {
                "wtimeout" : true
             },
             "errmsg" : "waiting for replication timed out"
          },
          {
             "code" : 64,
             "codeName" : "WriteConcernFailed",
             "errInfo" : {
                "wtimeout" : true
             },
             "errmsg" : "waiting for replication timed out"
          }
       ],
       "nInserted" : 1,
       "nUpserted" : 0,
       "nMatched" : 4,
       "nModified" : 4,
       "nRemoved" : 1,
       "upserted" : [ ]
    })

结果集显示执行的操作,因为writeConcernErrors错误不是任何写操作失败的指示。

译者:李冠飞

校对:

最后更新于