Overview
MongoDB provides clients the ability to perform write operations in bulk. Starting in MongoDB 8.0, you can perform bulk write operations across multiple databases and collections. If you are using a version earlier than MongoDB 8.0, you can perform bulk write operations on a single collection.
To perform bulk write operations across multiple databases and
collections in MongoDB 8.0, use the bulkWrite
database command or the Mongo.bulkWrite() mongosh method.
To perform bulk write operations on a single collection,
use the db.collection.bulkWrite() mongosh method. If you are
running MongoDB 8.0 or later, you can also use bulkWrite or
Mongo.bulkWrite() to write to a single collection.
Ordered vs Unordered Operations
You can set your bulk write operations to be either ordered or unordered.
With an ordered list of operations, MongoDB executes the operations serially. If an error occurs during the processing of one of the write operations, MongoDB returns without processing any remaining write operations in the list.
With an unordered list of operations, MongoDB can execute the operations in parallel, but this behavior is not guaranteed. If an error occurs during the processing of one of the write operations, MongoDB will continue to process remaining write operations in the list.
Executing an ordered list of operations on a sharded collection will generally be slower than executing an unordered list since with an ordered list, each operation must wait for the previous operation to finish.
By default, all bulk write commands and methods perform ordered operations.
To specify unordered operations, set the ordered option to false when you
call your preferred command or method. To learn more about the syntax of
each command or method, see their pages linked above.
Bulk Write Methods
All bulk write methods and commands support the following write operations:
Insert One
Update One
Update Many
Replace One
Delete One
Delete Many
When you call your preferred command or method, you pass each write operation as a document in an array. To learn more about the syntax of each command or method, see their pages linked above.
Example
The examples on this page use data from the sample_mflix sample dataset. For details on how to load this dataset into your self-managed MongoDB deployment, see Load the sample dataset. If you made any modifications to the sample databases, you may need to drop and recreate the databases to run the examples on this page.
db.collection.bulkWrite()
The db.collection.bulkWrite() example runs
the following operations on the users collection:
Adds two documents using
insertOne.Updates a document using
updateOne.Deletes a document using
deleteOne.Replaces a document using
replaceOne.
db.users.bulkWrite( [ { insertOne: { document: { _id: ObjectId("67a1b2c3d4e5f6a7b8c9d0e2"), name: "Daenerys Targaryen", email: "daenerys.t@example.com", password: "$2b$12$UREFwsRUoyF0CRqGNK0LzO0HM/jLhgUCNNIJ9RJAqMUQ74crlJ1Vu" } } }, { insertOne: { document: { _id: ObjectId("67a1b2c3d4e5f6a7b8c9d0e3"), name: "Jaime Lannister", email: "jaime.l@example.com", password: "$2b$12$UREFwsRUoyF0CRqGNK0LzO0HM/jLhgUCNNIJ9RJAqMUQ74crlJ1Vu" } } }, { updateOne: { filter: { name: "Ned Stark" }, update: { $set: { email: "ned.stark.updated@example.com" } } } }, { deleteOne: { filter: { name: "Daenerys Targaryen" } } }, { replaceOne: { filter: { name: "Jaime Lannister" }, replacement: { name: "Jaime Lannister", email: "jaime.lannister.new@example.com", password: "$2b$12$NewPasswordHashHere123456789012345678901234567890" } } } ] )
Example output, which includes a summary of the completed operations:
{ acknowledged: true, insertedCount: 2, insertedIds: { '0': ObjectId("67a1b2c3d4e5f6a7b8c9d0e2"), '1': ObjectId("67a1b2c3d4e5f6a7b8c9d0e3") }, matchedCount: 2, modifiedCount: 2, deletedCount: 1, upsertedCount: 0, upsertedIds: {} }
For more examples, see db.collection.bulkWrite() Examples.
Mongo.bulkWrite()
This example uses Mongo.bulkWrite() to perform the following
operations in order on the the sample_mflix database.
inserts a document into the
userscollectionupdates a document in the
theaterscollectioninserts another document into the
userscollection
db.getMongo().bulkWrite( [ { namespace: 'sample_mflix.users', name: 'insertOne', document: { name: 'Cersei Lannister', email: 'cersei.l@example.com', password: '$2b$12$UREFwsRUoyF0CRqGNK0LzO0HM/jLhgUCNNIJ9RJAqMUQ74crlJ1Vu' } }, { namespace: 'sample_mflix.theaters', name: 'updateOne', filter: { theaterId: 1000 }, update: { $set: { "location.address.street1": "350 W Market", "location.address.city": "Bloomington" } } }, { namespace: 'sample_mflix.users', name: 'insertOne', document: { name: 'Sansa Stark', email: 'sansa.s@example.com', password: '$2b$12$UREFwsRUoyF0CRqGNK0LzO0HM/jLhgUCNNIJ9RJAqMUQ74crlJ1Vu' } } ], { ordered: true, bypassDocumentValidation: true, verboseResults: true } )
mongosh performs the bulk write in order and returns the following
document:
{ acknowledged: true, insertedCount: 2, matchedCount: 1, modifiedCount: 1, deletedCount: 0, upsertedCount: 0, insertResults: Map(2) { 0 => { insertedId: "..." }, 2 => { insertedId: "..." } }, updateResults: Map(1) { 1 => { matchedCount: 1, modifiedCount: 1, didUpsert: false } }, deleteResults: Map(0) {} }
Strategies for Bulk Inserts to a Sharded Collection
Large bulk insert operations, including initial data inserts or routine data import, can affect sharded cluster performance. For bulk inserts, consider the following strategies:
Pre-Split the Collection
If your sharded collection is empty and you are not using hashed sharding for the first key of your shard key, then your collection has only one initial chunk, which resides on a single shard. MongoDB must then take time to receive data and distribute chunks to the available shards. To avoid this performance cost, pre-split the collection by creating ranges in a sharded cluster.
Unordered Writes to mongos
To improve write performance to sharded clusters, perform an unordered
bulk write by setting ordered to false when you call your
preferred method or command. mongos can attempt to send the writes to
multiple shards simultaneously. For empty collections,
first pre-split the collection as described in
Split Chunks in a Sharded Cluster.
Avoid Monotonic Throttling
If your shard key increases monotonically during an insert, then all inserted data goes to the last chunk in the collection, which will always end up on a single shard. Therefore, the insert capacity of the cluster will never exceed the insert capacity of that single shard.
If your insert volume is larger than what a single shard can process, and if you cannot avoid a monotonically increasing shard key, then consider the following modifications to your application:
Reverse the binary bits of the shard key. This preserves the information and avoids correlating insertion order with increasing sequence of values.
Swap the first and last 16-bit words to "shuffle" the inserts.
Example
The following example, in C++, swaps the leading and trailing 16-bit word of BSON ObjectIds generated so they are no longer monotonically increasing.
using namespace mongo; OID make_an_id() { OID x = OID::gen(); const unsigned char *p = x.getData(); swap( (unsigned short&) p[0], (unsigned short&) p[10] ); return x; } void foo() { // create an object BSONObj o = BSON( "_id" << make_an_id() << "x" << 3 << "name" << "jane" ); // now we may insert o into a sharded collection }
Tip
Shard Keys for information on choosing a sharded key. Also see Shard Key Internals (in particular, Choose a Shard Key).