MongoDB Bulk Writes and Partial Errors

Batch MongoDB inserts and updates with bulkWrite, compare ordered and unordered failure behavior, inspect failed indexes, and design safe reruns.

Lesson 29 of 43Intermediate10 min read

An import job may need to insert new records, update existing records, and remove obsolete records. bulkWrite groups these write models into a batching interface, reducing repetitive application calls. The important question is what happens when one model fails. A duplicate key can leave earlier writes completed, and an unordered batch can continue with other writes. This MongoDB 8.0 guide makes those outcomes observable in complete mongosh fixtures. It targets collection-level bulkWrite, not the separate newer cross-namespace bulk command. Every example resets only a named collection in a disposable teaching database.

Construct explicit write models

A collection bulk contains objects such as insertOne, updateOne, updateMany, replaceOne, deleteOne, or deleteMany with their documented arguments. Each model describes one operation, and its position in the submitted array identifies it for error reporting. Keep the original application record or job identifier associated with that position so a failed index can be reconciled with the source data. An error index is not necessarily a document's _id.

Validate source rows before creating models. Batching malformed data does not make it valid. Bound application batch size and retained result data so an import does not hold an entire enormous file in memory. Drivers and servers apply their own message and batch limits, but those are not a complete application concurrency policy. A single document still must satisfy BSON size and schema rules. Use collection-level models when all operations target the same collection and check the driver or server contract before assuming a cross-collection form is available.

Choose ordered or unordered semantics

An ordered bulk processes the models in order and stops at a write error under the documented behavior. Earlier successful writes remain completed. The main fixture inserts document two, then attempts a duplicate identifier, then would increment document one's quantity. In ordered mode, the duplicate prevents the later increment, but the earlier insert is still present. This is not an automatic rollback.

An unordered bulk can continue processing other operations despite individual errors, and applications must not rely on its execution order. Use it when the models are independent and partial progress is acceptable. The same fixture's later increment can complete in unordered mode. Do not submit dependent models such as create then update the newly created row while assuming unordered execution preserves that relationship. If order is part of correctness, select a suitable ordered workflow or transaction design. Performance is a reason to measure unordered batches, not permission to ignore semantic dependencies.

Inspect partial results and classify failures

A bulk error can contain per-operation writeErrors and information about successful work. Read the documented properties for the actual shell or driver version; interfaces are similar but not identical across APIs. Keep failed indexes and codes, and associate them with submitted models. A duplicate key may require fixing or treating an already existing identity as an expected state. A validation failure needs data correction. Retrying every failure blindly can reproduce the same permanent problem.

Write-concern failures and transport uncertainty are different from a clearly identified per-operation rejection. A request whose acknowledgement was lost may have partially or fully reached the server. Record enough job state to reconcile rather than assuming no work happened. Do not log entire sensitive documents just because a bulk failed. The fixture prints small deterministic summaries instead of dumping the whole error object. A production import can store per-record status and a checkpoint, with a policy distinguishing accepted, rejected, and uncertain rows.

Design reruns and atomicity explicitly

bulkWrite is a batching interface, not a transaction covering every model. Each appropriate single-document write retains its own atomicity, but several models can have partial outcomes. Use a transaction only when the required all-or-nothing business rule spans those writes and the deployment supports it. A large import may be better served by idempotent models, checkpoints, and reconciliation than by one enormous transaction. Make the chosen guarantee explicit to operators.

Rerunning a $set to a desired value can be idempotent, while repeating $inc can apply the change twice. Upsert with a unique business key can support repeatable imports when filters and indexes enforce the intended identity. It does not automatically solve every race or merge policy. The practice reruns deterministic $set models against unique SKU keys, showing that the second run does not create duplicate records or increase their quantities. Choose conflict handling for existing fields deliberately; replacement and update have different effects on fields the import does not own.

MongoDB documentation and version notes

MongoDB Bulk Writes and Partial Errors Examples

Each example shows the code, the output it produces and what each part does.

Example 1

Comparing ordered and unordered bulk failures

Run this complete script with mongosh on MongoDB 8.0. The helper resets a controlled collection before each comparison, seeds document one with quantity five, and submits three models. The duplicate is model index one. Ordered mode leaves quantity five because the later increment is skipped; unordered mode permits the increment and leaves quantity eight. Both modes retain the earlier valid insert. The summaries show identifiers and failed input indexes, making partial success clear. The demonstration uses independent later work, so it does not depend on an assumed execution order inside the unordered batch.

MongoDB Shell
const rows = db.getSiblingDB('codevra_ref_bulk').getCollection('ordering');
function run(ordered) {
  rows.deleteMany({});
  rows.insertOne({ _id: 1, qty: 5 });
  let failed = [];
  try {
    rows.bulkWrite([
      { insertOne: { document: { _id: 2, qty: 1 } } },
      { insertOne: { document: { _id: 1, qty: 99 } } },
      { updateOne: { filter: { _id: 1 }, update: { $inc: { qty: 3 } } } }
    ], { ordered });
  } catch (error) {
    if (!error.writeErrors) throw error;
    failed = error.writeErrors.map(item => item.index);
  }
  print(JSON.stringify({ ordered, qty: rows.findOne({ _id: 1 }).qty,
    ids: rows.find().sort({ _id: 1 }).toArray().map(x => x._id), failed }));
}
run(true);
run(false);
Output
{"ordered":true,"qty":5,"ids":[1,2],"failed":[1]}
{"ordered":false,"qty":8,"ids":[1,2],"failed":[1]}

MongoDB Bulk Writes and Partial Errors in Real Projects

Make a SKU import idempotent with upserts

Import two desired SKU quantities with upsert and a unique business-key index, then run the same bulk again. The solution uses $set for fields the import owns rather than $inc. Print each run's upsert count and the final SKU quantities. The first run creates two documents; the second matches those identities and creates none. This is a narrow idempotent fixture, not a guarantee that any upsert is safe to repeat. A production importer also needs a policy for deleted source rows, ownership of unrelated fields, and concurrent changes. The unique index establishes the intended SKU identity.

MongoDB Shell
const rows = db.getSiblingDB('codevra_ref_bulk').getCollection('stock');
rows.deleteMany({});
rows.createIndex({ sku: 1 }, { unique: true });
const models = [{ sku: 'A', qty: 5 }, { sku: 'B', qty: 7 }].map(row => ({
  updateOne: { filter: { sku: row.sku }, update: { $set: { qty: row.qty } }, upsert: true }
}));
const first = rows.bulkWrite(models, { ordered: false });
const second = rows.bulkWrite(models, { ordered: false });
print(first.upsertedCount);
print(second.upsertedCount);
print(JSON.stringify(rows.find({}, { _id: 0, sku: 1, qty: 1 }).sort({ sku: 1 }).toArray()));
Output
2
0
[{"sku":"A","qty":5},{"sku":"B","qty":7}]

MongoDB Bulk Writes and Partial Errors FAQ

Does an ordered error undo earlier writes?

No. Earlier successful models remain completed, while later models are not processed after the write error according to ordered semantics. The main fixture still contains document two after the duplicate fails. Use a supported transaction for a required multi-write all-or-nothing rule. Batching and atomicity are separate concerns, so an error report must describe partial progress rather than implying the entire input was rejected.

When is unordered appropriate?

When models are independent and the job can tolerate partial progress followed by reconciliation. Do not rely on model order in an unordered bulk. A create-then-update dependency or a business sequence may need another design. Measure the performance benefit with realistic data and preserve failed model indexes. Faster batching is useful only when it maintains the application's correctness and recovery policy.

Is an error index the failed document identifier?

No. It identifies the operation's position in the submitted models. Keep a mapping from that position to your source record or job key. A model can update many documents, so even that mapping is not always one-to-one with a stored _id. Report the code and intended operation carefully without dumping sensitive payloads. Inspect the actual driver's error shape rather than assuming every API returns identical objects.

Can I safely rerun every bulk after a network error?

Not blindly. Completion may be uncertain, and operations such as $inc can apply twice. Design idempotent writes or reconcile stored state using stable identities and job checkpoints. The practice's desired-value $set upserts are repeatable under their stated contract. A real importer needs to define conflict handling, fields it owns, and what happens to source records removed from a later run.

MongoDB Bulk Writes and Partial Errors Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Multiple choiceeasy

How many documents does the second worked SKU upsert bulk create?

MongoDB Bulk Writes and Partial Errors Quiz

2 questions to check what you learned.

  1. Why does quantity remain five in the ordered main run?

    • The duplicate error stops the later increment
    • Ordered mode rolls back the initial seed document
    • A bulk cannot contain update models
  2. Which repeated model can accidentally double-apply an adjustment?

    • An unconditional $inc of the same quantity
    • A $set to the same desired quantity
    • A read-only find projection