Bulk operations in MongoDB allow you to perform multiple write operations in a single request, significantly improving performance by reducing network overhead. Instead of making separate round trips for each operation, you batch them together and send to the database once.
MongoDB provides the bulkWrite method that accepts an array of operations including insertOne, updateOne, updateMany, deleteOne, deleteMany, and replaceOne. You can mix different operation types in a single bulk request. This is more efficient than executing operations individually, especially when dealing with large datasets or remote database connections.
The key distinction between ordered and unordered bulk operations lies in execution behavior and error handling. Ordered bulk operations execute in sequence, stopping at the first error. If an operation fails, all subsequent operations are cancelled. This maintains the order you specified and provides predictable behavior but means one failure stops the entire batch.
Unordered bulk operations execute in parallel with no guaranteed order, and continue executing all operations even if some fail. MongoDB may reorder operations for optimization. If multiple operations fail, all errors are collected and returned together at the end. This provides better performance because operations can be parallelized and one failure does not prevent other operations from succeeding.
Choose ordered bulk operations when operation order matters, such as when later operations depend on earlier ones, or when you need all-or-nothing semantics within the batch. For example, inserting a parent document before child documents that reference it.
Choose unordered bulk operations for maximum performance when operations are independent and order does not matter. This is common for batch inserts, mass updates, or data migrations where each operation stands alone. Unordered operations can be significantly faster for large batches.
Bulk operations return detailed results including how many documents were inserted, matched, modified, deleted, and any errors that occurred. Handle errors appropriately based on your requirements.
Example code
// ORDERED bulk operations (default)
try {
const result = await db.users.bulkWrite([
{ insertOne: { document: { name: "Alice", age: 25 } } },
{ insertOne: { document: { name: "Bob", age: 30 } } },
{ insertOne: { document: { name: "Alice" } } }, // Error: duplicate
{ insertOne: { document: { name: "David", age: 35 } } } // Not executed
], { ordered: true })
} catch (error) {
// First 2 succeed, 3rd fails, 4th never executed
console.log(error.writeErrors)
}
// UNORDERED bulk operations
try {
const result = await db.users.bulkWrite([
{ insertOne: { document: { name: "Alice", age: 25 } } },
{ insertOne: { document: { name: "Bob", age: 30 } } },
{ insertOne: { document: { name: "Alice" } } }, // Error: duplicate
{ insertOne: { document: { name: "David", age: 35 } } } // Still executed
], { ordered: false })
} catch (error) {
// 3 operations succeed, 1 fails, all errors reported
console.log(error.writeErrors)
}
// Mixed operations bulk write
const operations = [
{ insertOne: { document: { name: "Eve", age: 28 } } },
{ updateOne: {
filter: { name: "Alice" },
update: { $set: { age: 26 } }
}},
{ deleteOne: { filter: { name: "Bob" } } },
{ replaceOne: {
filter: { name: "Charlie" },
replacement: { name: "Charlie", age: 40, city: "NYC" }
}}
]
const result = await db.users.bulkWrite(operations, { ordered: false })
console.log(result)
// {
// insertedCount: 1,
// matchedCount: 2,
// modifiedCount: 2,
// deletedCount: 1,
// upsertedCount: 0
// }