Consistency in MongoDB
People arriving from the relational world often reach for a transaction the moment they need to change more than one thing. In MongoDB that instinct usually leads you astray. The database gives you a strong guarantee for free, and reaching past it for a multi-document transaction is something you do rarely and deliberately, not by default. This module is about understanding exactly what you already have, what you can ask for when you genuinely need more, and how to dial the durability and visibility of every operation up or down.
The single fact that everything else hangs on is this: a write to one document is atomic. When you update a member’s record, MongoDB applies the whole change — even if it touches a nested object, several fields, and an array all at once — as one indivisible step. No other reader ever sees the document half-changed, and if the write fails, the document is left exactly as it was. You do not open anything, you do not commit anything, and you do not pay any extra cost. The atomicity is simply how a document write works.
The shape of consistency here
Section titled “The shape of consistency here”Because one document is the unit of atomicity, the way you model your data decides how much of your consistency comes for free. Data that changes together and belongs together should live in the same document, so a single write keeps it consistent. When related data is genuinely spread across documents or collections and must change as a unit, MongoDB offers multi-document transactions — real ACID transactions across a session. They work, but they cost more and require a replica set, so they sit at the bottom of the toolbox rather than the top.
Layered on top of both is a pair of knobs that apply to every operation. A write concern controls how many replica-set members must acknowledge a write, and whether it must be flushed to the on-disk journal, before the driver calls the write done — this is the durability knob. A read concern controls how fresh and how committed the data you read must be — this is the visibility knob. Together they let you trade latency for safety, operation by operation.
flowchart TD
W["A write request"] --> Q{"How many documents?"}
Q -->|"One document"| A["Atomic automatically — no transaction needed"]
Q -->|"Many documents as a unit"| T["Multi-document transaction in a session"]
A --> WC["Write concern tunes durability"]
T --> WC
WC --> RC["Read concern tunes what readers see"] What this module covers
Section titled “What this module covers”- Single-document atomicity — why any change to one document, however deep, is all-or-nothing, and how to model data so this covers most of your needs.
- Multi-document transactions — opening a session, running several operations as one ACID unit, and committing or aborting, with the classic transfer-between-accounts example.
- Read and write concerns — the
w,j, andwtimeoutsettings for writes, thelocal,majority, andlinearizablelevels for reads, and read preference for choosing which member answers. - Change streams — subscribing to a live feed of inserts, updates, and deletes so your application can react to data changes as they happen.
What the lessons proved
Section titled “What the lessons proved”- Single-document atomicity — a failing update changed nothing; 100 concurrent read-modify-writes lost most increments while
$incdid not;updateManywas observed half-applied. - Transactions — rollback,
WriteConflictwith the retry label, the 60 s lifetime, and a forgotten{ session }that silently committed a debit. - Concerns — the default write concern is already
w: "majority"; aw: 1write acknowledged by a partitioned primary was rolled back; aw: 3timeout still applied the write. - Change streams — the Node driver opens lazily and misses an insert made right after
watch(); real resume tokens are 188 hex characters.
Mental Model
Section titled “Mental Model”One document is the unit of atomicity and costs nothing. Everything bigger is a sequence of atomic steps you must either fold into one document, guard in a filter, or wrap in a transaction. Concerns are two independent dials on top: write concern is what the writer is told, read concern is what the reader sees.
Trade-offs
Section titled “Trade-offs”| Choice | Benefit | Cost |
|---|---|---|
| Design documents so single-document atomicity covers the need | Atomicity for free, no session or commit overhead, lowest latency (about half a transaction’s time in the measured run) | Requires upfront schema thought; does not fit data that truly must stay independent entities |
| Multi-document transaction (full ACID) | Guarantees correctness across documents and collections | Needs a replica set, retries on WriteConflict, 60 s limit |
Write concern w: "majority" (the default) | An acknowledged write survives a failover | Waits for replication; times out if a majority is unreachable |
Read concern majority | No reads of data that can be rolled back | Lags local and your own w: 1 writes |
Common Misconceptions
Section titled “Common Misconceptions”- “Reach for a transaction whenever more than one document is touched.” — first ask whether the data that changes together can live together; the single-document write was the cheapest in every measurement.
- “Write concern and read concern are the same knob.” — durability for the writer versus visibility for the reader; they are independent.
- “Set the strongest concern everywhere.” — the default is already majority; the deliberate, risky choice is lowering it.
- “An acknowledged write is safe.” — only if the concern covers a majority; a
w: 1acknowledgement was rolled back after a partition.