db.collection.insertMany()
带驱动程序的 MongoDB
本页面提供 mongosh
方法的相关信息。要查看 MongoDB 驱动程序中的等效方法,请参阅编程语言的相应页面:
定义
db.collection.insertMany()
将多个文档插入到一个集合中。
返回: 文档包含以下内容:
一个
acknowledged
布尔值,如果操作在true
写关注(write concern)下运行,则设立为 ;如果禁用写关注(writefalse
concern),则设置为一个
insertedIds
数组,包含每份成功插入的文档的_id
值
兼容性
可以使用 db.collection.insertMany()
查找托管在以下环境中的部署:
MongoDB Atlas:用于云中 MongoDB 部署的完全托管服务
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
insertMany()
方法使用的语法如下:
db.collection.insertMany( [ <document 1> , <document 2>, ... ], { writeConcern: <document>, ordered: <boolean> } )
行为
对于给定的文档数组,insertMany()
可将该数组中的每个文档插入到相应集合中。
执行操作
默认情况下,文档按顺序插入。
如果将ordered
设立为 false,则以无序格式插入文档,并且可以由mongod
重新排序以提高性能。 如果使用无序insertMany()
,则应用程序不应依赖插入的顺序。
每组中的操作次数不能超过数据库的maxWriteBatchSize值。 从 MongoDB 3.6 开始,此值为100,000
。 该值会显示在hello.maxWriteBatchSize
字段中。
此限制可防止错误消息过大的问题。如果一个群组超过此限制,则客户端驱动程序会将该群组分成计数小于或等于限制值的更小群组。例如,对于 maxWriteBatchSize
值为 100,000
的情况,如果队列由 200,000
个操作组成,则驱动程序将创建 2 个群组,每个群组包含 100,000
个操作。
注意
驱动程序仅在使用高级 API 时才会将群组划分为更小的群组。 如果直接使用db.runCommand() (例如,在编写驱动程序时),MongoDB 在尝试执行超过限制的写入批处理时会引发错误。
从 MongoDB 3.6 开始,一旦单个批处理的错误报告变得太大,MongoDB 会将所有剩余错误消息截断为空字符串。 目前,一旦存在至少 2 条总大小大于1MB
的错误消息,就会开始。
大小和分组机制是内部性能细节,在未来版本中可能会有变化。
在分片集合上执行操作的 ordered
列表通常比执行 unordered
列表慢,因为对于有序列表,每个操作都必须等待前一个操作完成。
创建集合
如果该集合不存在,则 insertMany()
会在成功写入时创建该集合。
_id
字段
如果文档未指定 _id 字段,mongod
则会添加 _id
字段并为该文档分配一个唯一 ObjectId()
。大多数驱动程序均会创建一个 ObjectId 并插入 _id
字段;如果驱动程序或应用程序未执行上述操作,mongod
则会创建并填充 _id
。
如果文档包含 _id
字段,则 _id
值在集合中必须是唯一的,以避免重复键错误。
可解释性
Error Handling
插入会引发 BulkWriteError
异常。
不包括写关注错误,有序操作会在出错后停止,而无序操作则会继续处理队列中剩余的写入操作。
写关注错误显示在 writeConcernErrors
字段,所有其他错误则显示在 writeErrors
字段。如果遇到错误,则会显示成功写操作的数量,而不是插入的 _ids 列表。有序操作显示遇到的单个错误,而无序操作则以数组形式显示每个错误。
模式验证错误
如果您的集合使用模式验证并将 validationAction
设置为 error
,则插入带有 db.collection.insertMany()
无效文档会引发 writeError
。在 documents
数组中,无效文档前面的文档将写入集合。ordered
字段的值确定是否插入其余有效文档。
事务
db.collection.insertMany()
可以在分布式事务中使用。
重要
在大多数情况下,与单文档写入操作相比,分布式事务会产生更高的性能成本,并且分布式事务的可用性不应取代有效的模式设计。在许多情况下,非规范化数据模型(嵌入式文档和数组)仍然是数据和使用案例的最佳选择。换言之,对于许多场景,适当的数据建模将最大限度地减少对分布式事务的需求。
有关其他事务使用注意事项(如运行时间限制和 oplog 大小限制),另请参阅生产注意事项。
在事务中创建集合
如果事务不是跨分片写事务,则可以在分布式事务中创建集合和索引。
如果在事务中对不存在的集合指定插入操作,则 MongoDB 会隐式创建该集合。
写关注和事务
如果是在事务中运行,则请勿显式设置此操作的写关注。要将写关注与事务一起使用,请参阅事务和写关注。
随机数据的性能考量
如果某操作在已索引字段上插入大量随机数据(例如,哈希索引),插入性能可能会降低。随机数据的批量插入会创建随机索引条目,从而增加索引的大小。如果索引达到需要每次随机插入都访问不同索引条目的大小,则插入操作会导致较高的 WiredTiger 缓存逐出和替换速度。发生这种情况时,索引不再完全位于缓存中,而是在磁盘上更新,这会降低性能。
要提高在已索引字段上批量插入随机数据的性能,可以采用以下两种方法之一:
删除索引,然后在插入随机数据后重新创建该索引。
将数据插入一个空的无索引集合。
批量插入后创建索引会对内存中的数据排序并对所有索引执行有序插入。
Oplog 条目
如果 db.collection.insertMany()
操作成功插入了一个或多个文档,则该操作会为每个插入的文档在 oplog(操作日志)上添加一个条目。如果操作失败,则该操作不会为 oplog 添加条目。
示例
以下示例会将文档插入到 products
集合。
插入多份文档而不指定 _id
字段
下面的示例使用 db.collection.insertMany()
插入不包含 _id
字段的文档:
try { db.products.insertMany( [ { item: "card", qty: 15 }, { item: "envelope", qty: 20 }, { item: "stamps" , qty: 30 } ] ); } catch (e) { print (e); }
该操作将返回以下文档:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("562a94d381cb9f1cd6eb0e1a"), ObjectId("562a94d381cb9f1cd6eb0e1b"), ObjectId("562a94d381cb9f1cd6eb0e1c") ] }
由于文档不包含 _id
,因此 mongod
会为每个文档创建并添加 _id
字段,并为其分配一个唯一的 ObjectId()
值。
ObjectId
值特定于运行操作时的设备和时间。因此,您的值可能与示例中的值不同。
插入多个指定 _id
字段的文档
以下示例/操作使用 insertMany()
插入包含 _id
字段的文档。_id
的值在集合中必须是唯一的,以避免出现重复键错误。
try { db.products.insertMany( [ { _id: 10, item: "large box", qty: 20 }, { _id: 11, item: "small box", qty: 55 }, { _id: 12, item: "medium box", qty: 30 } ] ); } catch (e) { print (e); }
该操作将返回以下文档:
{ "acknowledged" : true, "insertedIds" : [ 10, 11, 12 ] }
为属于唯一索引的任何键插入重复值(例如 _id
)会引发异常。下面的例子中尝试插入一个已存在 _id
值的文档:
try { db.products.insertMany( [ { _id: 13, item: "envelopes", qty: 60 }, { _id: 13, item: "stamps", qty: 110 }, { _id: 14, item: "packing tape", qty: 38 } ] ); } catch (e) { print (e); }
由于 _id: 13
已存在,因此会抛出以下异常:
BulkWriteError({ "writeErrors" : [ { "index" : 0, "code" : 11000, "errmsg" : "E11000 duplicate key error collection: inventory.products index: _id_ dup key: { : 13.0 }", "op" : { "_id" : 13, "item" : "stamps", "qty" : 110 } } ], "writeConcernErrors" : [ ], "nInserted" : 1, "nUpserted" : 0, "nMatched" : 0, "nModified" : 0, "nRemoved" : 0, "upserted" : [ ] })
请注意,此时已插入一个文档:_id: 13
的第一个文档将成功插入,但第二个插入会失败。此举也会阻止插入队列中剩余的其他文档。
如果 ordered
为 false
,则插入操作将继续处理剩余文档。
无序插入
以下尝试插入具有 _id
字段和 ordered: false
的多个文档。文档数组包含两个具有重复 _id
字段的文档。
try { db.products.insertMany( [ { _id: 10, item: "large box", qty: 20 }, { _id: 11, item: "small box", qty: 55 }, { _id: 11, item: "medium box", qty: 30 }, { _id: 12, item: "envelope", qty: 100}, { _id: 13, item: "stamps", qty: 125 }, { _id: 13, item: "tape", qty: 20}, { _id: 14, item: "bubble wrap", qty: 30} ], { ordered: false } ); } catch (e) { print (e); }
此操作会引发以下异常:
BulkWriteError({ "writeErrors" : [ { "index" : 2, "code" : 11000, "errmsg" : "E11000 duplicate key error collection: inventory.products index: _id_ dup key: { : 11.0 }", "op" : { "_id" : 11, "item" : "medium box", "qty" : 30 } }, { "index" : 5, "code" : 11000, "errmsg" : "E11000 duplicate key error collection: inventory.products index: _id_ dup key: { : 13.0 }", "op" : { "_id" : 13, "item" : "tape", "qty" : 20 } } ], "writeConcernErrors" : [ ], "nInserted" : 5, "nUpserted" : 0, "nMatched" : 0, "nModified" : 0, "nRemoved" : 0, "upserted" : [ ] })
虽然包含 item: "medium box"
和 item: "tape"
的文档由于存在重复的 _id
值而未能插入,nInserted
显示其余 5 个文档已插入。
使用写关注
给定一个三成员副本集,以下操作指定 majority
的 w
和 100
的 wtimeout
:
try { db.products.insertMany( [ { _id: 10, item: "large box", qty: 20 }, { _id: 11, item: "small box", qty: 55 }, { _id: 12, item: "medium box", qty: 30 } ], { w: "majority", wtimeout: 100 } ); } catch (e) { print (e); }
如果主节点和至少一个从节点在 100 毫秒内确认每个写入操作,则返回:
{ "acknowledged" : true, "insertedIds" : [ ObjectId("562a94d381cb9f1cd6eb0e1a"), ObjectId("562a94d381cb9f1cd6eb0e1b"), ObjectId("562a94d381cb9f1cd6eb0e1c") ] }
如果副本集中所有必需节点确认写入操作所需的总时间大于 wtimeout
,则在经过wtimeout
时间段后将显示以下 writeConcernError
。
此操作返回:
WriteConcernError({ "code" : 64, "errmsg" : "waiting for replication timed out", "errInfo" : { "wtimeout" : true, "writeConcern" : { "w" : "majority", "wtimeout" : 100, "provenance" : "getLastErrorDefaults" } } })