Module: MongoDB
MongoDB·139·6 MIN READ

139: MongoDB Consistency — Atomicity, Transactions, Sessions, Read Concern, Write Concern, Read Preference, and Retryable Operations

TOPICS COVERED: MongoDB Consistency — Atomicity, Transactions, Sessions, Read Concern, Write Concern, Read Preference, and Retryable Operations

Learning objectives

You will learn to:

  • understand single-document atomicity;
  • use conditional atomic updates;
  • understand sessions;
  • use multi-document transactions;
  • choose transaction boundaries;
  • understand read concern;
  • understand write concern;
  • understand read preference;
  • understand causal consistency at a practical level;
  • understand retryable reads/writes;
  • design idempotent application behavior;
  • avoid treating transactions as a substitute for good schema design.

Single-document atomicity

MongoDB writes to one document atomically.

Example:

javascript
db.accounts.updateOne(
  {
    _id: accountId,
    balancePaise: {
      $gte: 5000
    }
  },
  {
    $inc: {
      balancePaise: -5000,
      version: 1
    }
  }
)

The predicate and update are evaluated atomically for that document.

This can enforce:

text
do not reduce balance below zero

without a read-then-write race.

Read-modify-write race

Unsafe pattern:

text
read balance = 100
request A subtracts 30
request B subtracts 50
A writes 70
B writes 50

One update is lost.

Use atomic update operators/predicate:

javascript
{
  $inc: {
    balance: -amount
  }
}

with condition.

Or optimistic version:

javascript
filter:
{
  _id,
  version: expected
}

update:
{
  $set: patch,
  $inc: {
    version: 1
  }
}

If matched count 0:

text
conflict

When one document is enough

If order + line items + totals are embedded:

text
mark line served
update order total/status

can often be one atomic document update.

If you normalized into many collections, you may need transaction.

This is why modeling and transaction design are connected.

Multi-document transaction

Use when one business invariant spans multiple documents/collections.

Example transfer:

text
debit account A
credit account B
insert transfer record

should commit together.

Transactions support ACID semantics across involved documents on supported deployments.

Session

Transactions run in client session.

Node driver example is lesson 144.

Shell concept:

javascript
const session = db.getMongo().startSession()

session.startTransaction()

try {
  ...
  session.commitTransaction()
} catch (error) {
  session.abortTransaction()
  throw error
} finally {
  session.endSession()
}

Exact shell APIs can vary; driver API is primary application interface.

Transaction design

Keep transactions:

  • short;
  • focused;
  • bounded;
  • minimal documents;
  • no user waiting inside;
  • no slow external API calls.

Do not:

text
start Mongo transaction
→ call payment API for 20 seconds
→ wait user confirmation
→ commit

External systems cannot participate in Mongo transaction.

Use saga/outbox/idempotency architecture for cross-system consistency.

Transaction retry

Transactions can encounter transient errors requiring retry.

Official drivers provide helpers such as withTransaction that handle certain retry semantics.

Use driver-recommended API.

Do not write naive infinite retry.

Keep operation idempotent where possible.

Transaction performance

Transactions add:

  • coordination;
  • snapshot state;
  • oplog/replication pressure;
  • memory/storage;
  • contention.

Do not wrap every CRUD request in transaction “for safety.”

Single-document atomicity is cheaper.

Snapshot isolation concept

Transaction reads see a consistent snapshot according to transaction/read concern semantics.

Concurrent changes may cause conflicts/retries.

Understand that “transaction” does not mean no concurrency; it means controlled consistency/isolation semantics.

Read concern

Read concern controls consistency/isolation guarantees of reads.

Common levels include concepts such as:

text
local
available
majority
linearizable
snapshot

Availability depends on deployment/operation.

Do not memorize names without semantics.

local

Can return latest data on node without guaranteeing majority replication.

May see data later rolled back in rare failover scenarios.

majority

Returns data acknowledged as committed to majority, according to replication semantics.

Often chosen when reading durable committed data matters.

Has latency/availability trade-offs.

linearizable

Strong single-document read semantics in specific supported contexts, with higher cost/constraints.

Use only when requirement demands.

snapshot

Used for snapshot-consistent reads/transactions under supported scenarios.

Write concern

Controls acknowledgment requirement for writes.

Examples:

javascript
{
  w: 1
}

acknowledge by primary.

javascript
{
  w: "majority"
}

wait for majority acknowledgment.

Optional:

text
j: true
wtimeout

depending requirements/version.

Do not assume acknowledged write = globally visible to every read preference instantly.

Durability trade-off

Higher write concern can increase durability and latency.

For critical financial-like data, stronger acknowledgment may be appropriate.

For disposable telemetry, different policy could fit.

Choose from business durability requirement.

Write concern timeout

If required acknowledgment not achieved in time, client can receive timeout even if write may have been applied on some nodes.

Application must handle ambiguous outcomes carefully.

This is why idempotency keys/version checks matter.

Read preference

Controls which replica-set member can serve reads.

Common modes:

text
primary
primaryPreferred
secondary
secondaryPreferred
nearest

Primary gives freshest primary view.

Secondary can reduce primary read load or serve regional reads but may be stale.

Do not use secondary reads for authorization/critical read-after-write behavior without understanding lag/consistency.

Stale secondary

Flow:

text
write primary
immediate read secondary
→ old value

Possible depending lag/read concern.

If user expects immediate confirmation, choose appropriate read path.

Causal consistency

Sessions can support causal relationships so later operations observe prior operations in expected order under supported settings.

Useful for:

text
write
then read in same logical session

without strongest global consistency everywhere.

Drivers manage metadata.

Retryable writes

Driver may automatically retry selected single-document writes after transient network/primary errors.

This improves reliability while avoiding duplicate effects because server tracks retryable operation identity in supported sessions.

Do not assume arbitrary multi-step application workflow is automatically retry-safe.

Retryable reads

Selected reads can retry after transient errors.

A retry can increase latency during failover but improve success.

Use driver defaults/recommendations.

Ambiguous outcome

Imagine:

text
client sends create
server commits
network drops before response

Client does not know if create happened.

If retry creates another record, duplicate.

Solutions:

  • client-generated stable operation/resource ID;
  • unique external ID;
  • idempotency key;
  • retryable-write semantics where applicable.

Unique index + idempotency

Webhook event:

json
{
  "eventId": "evt_123"
}

Create processing record with unique index:

javascript
{
  eventId: 1
}
unique

If webhook retries, duplicate key tells you already processed/claimed.

Still design transaction around side effects.

Transaction and outbox

Need:

text
update order
publish event

Mongo transaction cannot atomically publish to Kafka/external broker.

Outbox pattern:

Transaction writes:

text
order update
outbox event document

Then worker publishes outbox reliably and marks sent.

This connects DB atomicity to external messaging.

Change streams alternative

Change streams can observe committed changes, but delivery/resume semantics and business event shape need design.

Do not assume raw database change stream equals durable business-event outbox for every requirement.

Advanced lesson covers.

Isolation and counters

Atomic counter:

javascript
findOneAndUpdate(
  { _id: "invoice" },
  { $inc: { next: 1 } },
  { returnDocument: "after" }
)

One hot counter can become contention bottleneck at high scale.

For strict invoice sequences, domain/legal requirements may demand serialization; design capacity intentionally.

Distributed transactions and sharding

Transactions work in sharded clusters with additional coordination cost.

If every request touches many shards, shard key/data model may be poor.

Sharding lesson goes deeper.

Read/write concern defaults

Driver/cluster defaults evolve.

Do not copy ancient options from tutorials.

Use explicit concerns for operations where business semantics differ from defaults and document why.

Error labels

Mongo driver errors can include labels such as transient transaction concepts.

Use official driver helpers rather than string matching error messages.

Failure clinic

  • transaction around every request;
  • long external API inside transaction;
  • read from secondary expecting immediate write;
  • weaker write concern for critical data without decision;
  • retry loop on unknown outcome creates duplicates;
  • application pre-check uniqueness without unique index;
  • transaction used to compensate for bad embedding;
  • no idempotency on webhook/payment create;
  • raw change stream treated as business outbox automatically.

Exercises

  1. Build atomic decrement with predicate.
  2. Implement versioned update.
  3. Model transfer requiring transaction.
  4. Identify workflow that should avoid transaction by embedding.
  5. Compare w:1 versus majority business trade-off.
  6. Simulate read-after-write from secondary conceptually.
  7. Design idempotent webhook handling.
  8. Design outbox transaction.
  9. Explain ambiguous create outcome.
  10. Create consistency matrix for payment, profile, analytics event.

Mastery checklist

Explain:

  • single-document atomicity;
  • conditional updates;
  • sessions;
  • transactions;
  • read concern;
  • write concern;
  • read preference;
  • causal consistency;
  • retryable reads/writes;
  • ambiguous outcomes;
  • idempotency;
  • outbox.

Official references