带驱动程序的 MongoDB
定义
db.collection.insertMany()将多个文档插入到一个集合中。
返回: 文档包含以下内容:
如果操作在写关注下运行,则
acknowledged布尔值设置为true;如果禁用写关注,则设置为false一个
insertedIds数组,包含每份成功插入的文档的_id值
兼容性
此方法可用于以下环境中托管的部署:
- 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.
MongoDB Enterprise:基于订阅、自我管理的 MongoDB 版本
MongoDB Community:源代码可用、免费使用且可自行管理的 MongoDB 版本
语法
db.collection.insertMany() 通过以下语法实现:
db.collection.insertMany( [ <document 1> , <document 2>, ... ], { writeConcern: <document>, ordered: <boolean> } )
参数
行为
对于给定的文档数组,insertMany() 可将该数组中的每个文档插入到相应集合中。您可以在数组中指定的文档数量没有限制。
执行操作
默认情况下,文档会按其提供的顺序插入。
如果
ordered设置为true并且插入失败,则服务器不会继续插入记录。如果
ordered设为false且插入操作失败,服务器会继续插入记录。文档可按mongod重新排序,从而提高性能。如果使用无序insertMany(),应用程序不应依赖插入的顺序。
在分片集合上执行操作的 ordered 列表通常比执行 unordered 列表慢,因为对于有序列表,每个操作都必须等待前一个操作完成。
批处理
驱动程序会根据 maxWriteBatchSize(即 100,000,且不可修改)对 insertMany() 数组中指定的文档进行批处理。例如,如果 insertMany() 操作包含 250,000 个文档,则驱动程序会创建三个批处理:两个批处理包含 100,000 个文档,另一个批处理包含 50,000 个文档。
注意
驱动程序仅在使用高级 API 时执行批处理。如果直接使用 db.runCommand()(例如,在编写驱动程序时),MongoDB 在尝试执行超过 maxWriteBatchSize 限制的写入批处理时会引发错误。
如果单个批处理的错误报告变得过大,MongoDB 会截断所有剩余的错误消息。如果存在至少两条大小超过 1MB 的错误消息,这些消息将会被截断。
大小和分组机制是内部性能细节,在未来版本中可能会有变化。
集合与_id字段创建
如果该集合不存在,则insertMany()会创建该集合。
如果文档未指定 _id 字段,则 mongod 会添加 _id 字段,并为该文档分配唯一的 ObjectId()。大多数驱动程序都会创建一个 ObjectId 并插入 _id 字段,如果驱动程序或应用程序不这样做,则 mongod 将创建并填充 _id。
如果文档包含 _id 字段,则 _id 值在集合中必须是唯一的,以避免重复键错误。
可解释性
insertMany() 与db.collection.explain() 不兼容。
Error Handling
插入会引发 BulkWriteError 异常。
不包括写关注错误,有序操作会在出错后停止,而无序操作则会继续处理队列中剩余的写入操作。
写关注错误显示在 writeConcernErrors 字段,所有其他错误则显示在 writeErrors 字段。如果遇到错误,则会显示成功写操作的数量,而不是插入的 _ids 列表。有序操作显示遇到的单个错误,而无序操作则以数组形式显示每个错误。
模式验证错误
如果您的集合使用模式验证并将 validationAction 设置为 error ,则插入带有 insertMany() 无效文档会引发 writeError 。在 documents 数组中,无效文档前面的文档将写入集合。ordered 字段的值确定是否插入其余有效文档。
事务
insertMany() 可用于分布式事务。
重要
在大多数情况下,与单文档写入操作相比,分布式事务会产生更高的性能成本,并且分布式事务的可用性不应取代有效的模式设计。在许多情况下,非规范化数据模型(嵌入式文档和数组)仍然是数据和使用案例的最佳选择。换言之,对于许多场景,适当的数据建模将最大限度地减少对分布式事务的需求。
有关其他事务使用注意事项(如运行时间限制和 oplog 大小限制),另请参阅生产注意事项。
在事务中创建集合
如果分布式事务不是跨分片写入事务,则可以在该事务中创建集合和索引。
如果在事务中对不存在的集合指定插入操作,则 MongoDB 会隐式创建该集合。
写关注和事务
如果是在事务中运行,则请勿显式设置此操作的写关注。要将写关注与事务一起使用,请参阅事务和写关注。
随机数据的性能考量
如果某操作在已索引字段上插入大量随机数据(例如,哈希索引),插入性能可能会降低。随机数据的批量插入会创建随机索引条目,从而增加索引的大小。如果索引达到需要每次随机插入都访问不同索引条目的大小,则插入操作会导致较高的 WiredTiger 缓存逐出和替换速度。发生这种情况时,索引不再完全位于缓存中,而是在磁盘上更新,这会降低性能。
要提高在已索引字段上批量插入随机数据的性能,可以采用以下两种方法之一:
删除索引,然后在插入随机数据后重新创建该索引。
将数据插入一个空的无索引集合。
批量插入后创建索引会对内存中的数据排序并对所有索引执行有序插入。
Oplog 条目
MongoDB 将插入多个文档的操作(例如 insertMany() 或 db.collection.bulkWrite() 操作中的多个 insertOne() 命令)整合到 oplog 中的单个条目中。如果操作失败,则该操作不会为 oplog 添加条目。
示例
本页上的示例使用来自 sample_mflix 数据集的数据。有关如何将此数据集加载到您的自管理 MongoDB 部署中的详细信息,请参阅 加载示例数据集。如果您对示例数据库进行了任何修改,您可能需要删除并重新创建数据库,才能运行此页面上的示例。
插入多个文档而不指定 _id 字段
以下示例将三个没有 _id 字段的文档插入到 movies集合中:
db.movies.insertMany( [ { title: "Inception", year: 2010, genres: [ "Action", "Sci-Fi" ] }, { title: "The Matrix", year: 1999, genres: [ "Action", "Sci-Fi" ] }, { title: "Interstellar", year: 2014, genres: [ "Adventure", "Sci-Fi" ] } ] )
{ acknowledged: true, insertedIds: { '0': "...", '1': "...", '2': "..." } }
由于文档不包含 _id,因此mongod会为每个文档创建并添加_id字段,并为其分配唯一的ObjectId()值。
ObjectId 值特定于运行操作时的设备和时间。因此,您的值可能与示例中的值不同。
插入多个指定 _id 字段的文档
以下示例将指定 _id字段的文档插入到 movies集合中。_id 的值在集合内必须是唯一的,以避免重复键错误:
db.movies.insertMany( [ { _id: 10, title: "Inception", year: 2010 }, { _id: 11, title: "The Matrix", year: 1999 }, { _id: 12, title: "Interstellar", year: 2014 } ] )
{ acknowledged: true, insertedIds: { '0': 10, '1': 11, '2': 12 } }
为属于唯一索引的任何键插入重复值(例如 _id)会引发异常。下面的例子中尝试插入一个已存在 _id 值的文档:
try { db.movies.insertMany( [ { _id: 13, title: "Inception", year: 2010 }, { _id: 13, title: "The Dark Knight", year: 2008 }, { _id: 14, title: "Interstellar", year: 2014 } ] ); } catch (e) { print (e); }
由于 _id: 13 已存在,因此会抛出以下异常:
BulkWriteError({ "writeErrors" : [ { "index" : 0, "code" : 11000, "errmsg" : "E11000 duplicate key error collection: sample_mflix.movies index: _id_ dup key: { : 13.0 }", "op" : { "_id" : 13, "title" : "The Dark Knight", "year" : 2008 } } ], "writeConcernErrors" : [ ], "nInserted" : 1, "nUpserted" : 0, "nMatched" : 0, "nModified" : 0, "nRemoved" : 0, "upserted" : [ ] })
请注意,已插入一个文档:_id: 13 的第一个文档插入成功,但第二个插入失败。该操作不会插入队列中的剩余文档。
将 ordered设立为 false 时,插入操作将继续处理剩余的文档。
无序插入
以下尝试插入具有 _id 字段和 ordered: false 的多个文档。文档数组包含两个具有重复 _id 字段的文档。
try { db.movies.insertMany( [ { _id: 10, title: "Inception", year: 2010 }, { _id: 11, title: "The Matrix", year: 1999 }, { _id: 11, title: "Interstellar", year: 2014 }, { _id: 12, title: "Arrival", year: 2016 }, { _id: 13, title: "Blade Runner 2049", year: 2017 }, { _id: 13, title: "Ex Machina", year: 2014 }, { _id: 14, title: "Her", year: 2013 } ], { ordered: false } ) } catch (e) { print(e) }
MongoBulkWriteError: E11000 duplicate key error collection: sample_mflix.movies index: _id_ dup key: { _id: 11 } Result: BulkWriteResult { insertedCount: 5, matchedCount: 0, modifiedCount: 0, deletedCount: 0, upsertedCount: 0, upsertedIds: {}, insertedIds: { '0': 10, '1': 11, '3': 12, '4': 13, '6': 14 } } Write Errors: [ WriteError { err: { index: 2, code: 11000, errInfo: undefined, errmsg: 'E11000 duplicate key error collection: sample_mflix.movies index: _id_ dup key: { _id: 11 }' } }, WriteError { err: { index: 5, code: 11000, errInfo: undefined, errmsg: 'E11000 duplicate key error collection: sample_mflix.movies index: _id_ dup key: { _id: 13 }' } } ]
尽管具有 title: "Interstellar" 和 title: "Ex Machina" 的文档由于重复的 _id 值而无法插入,但 insertedCount 显示其余 5 文档插入成功。
使用写关注
给定一个三成员副本集,以下操作指定 majority 的 w 和 100 的 wtimeout:
try { db.movies.insertMany( [ { _id: 15, title: "Forrest Gump", year: 1994 }, { _id: 16, title: "Schindler's List", year: 1993 }, { _id: 17, title: "Pulp Fiction", year: 1994 } ], { 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" } } })