MongoDB Mastery
MongoDB Mastery lessons / Module 19: Read & Write Concerns

Write concern, read concern and read preference

Level 3: Advanced28 min

Tune durability, consistency and routing per operation: w and j, local/majority/snapshot/linearizable reads, primary/secondary routing and causal consistency.

This lesson is interactive. Run every example against an in-browser MongoDB, see explain() plans drawn as trees, and take the quiz.
Open the interactive lesson
You will learn to
  • Choose write concern: w: 1, w: "majority", j: true, wtimeout
  • Choose read concern: local, available, majority, snapshot, linearizable
  • Route reads with read preference and maxStalenessSeconds
  • Explain rollback risk and causal consistency

conceptThe concept

Open the interactive lesson to use this diagram.

Write concern is how many members must acknowledge a write before the client is told it succeeded. w: 1: primary only. w: "majority" (default since 5.0): a majority of voting members, which means the write survives any failover. j: true: written to the on-disk journal. wtimeout: stop waiting (the write is not undone).

Read concern is which data a read may return:

  • local (default): the latest data on that node, which might later be rolled back.
  • available: like local; on sharded clusters may return orphans. Fastest.
  • majority: only data acknowledged by a majority; never rolled back.
  • snapshot: a consistent point-in-time view (transactions, and reads with atClusterTime).
  • linearizable: reflects all majority writes completed before the read started; primary only, slow.

Read preference is where reads go: primary (default), primaryPreferred, secondary, secondaryPreferred, nearest, optionally with tag sets and maxStalenessSeconds (90 or more).

whyWhy it matters

These settings are the dial between latency and safety. With w: 1, a write acknowledged by a primary that crashes before replicating it is rolled back after failover, and the client thinks it succeeded. With secondary reads, a user may not see the profile change they just saved. Knowing these trade-offs is essential for architects and a common interview topic.

Use caseReal-world scenario

Payments use w: "majority" and read their own writes from the primary. The analytics dashboard reads from a secondary tagged { workload: "analytics" } with secondaryPreferred, accepting a few seconds of lag. A "user just updated settings" flow uses causally consistent sessions so a subsequent secondary read waits until it has caught up to that write.

Try itExamples

Run and edit these in the interactive lesson.

Write concern per operation
db.orders.insertOne({ orderNo: "ORD-WC-1", status: "paid", createdAt: new Date(), total: 10 }, { writeConcern: { w: "majority", j: true, wtimeout: 5000 } })
db.orders.updateOne({ orderNo: "ORD-WC-1" }, { $set: { status: "shipped" } }, { writeConcern: { w: 1 } })
Read preference and read concern
db.orders.find({ status: "shipped" }).readPref("secondaryPreferred").readConcern("majority").limit(2)
db.adminCommand({ getDefaultRWConcern: 1 })
This simulator is a single node, so the routing options are accepted but every read comes from the same node. The Architecture page simulates the replica set.
Connection string options
mongodb://db1,db2,db3/shop?replicaSet=rs0&w=majority&readPreference=secondaryPreferred&maxStalenessSeconds=120&readPreferenceTags=dc:east

internalsUnder the hood

The primary tracks each secondary's replicated optime. A majority write waits until the majority commit point passes its optime. Majority reads serve data from the majority-committed snapshot, which WiredTiger keeps available; if secondaries lag, that snapshot stays old and pins history in the cache (cache pressure on the primary). Causal consistency works by carrying operationTime/clusterTime from one operation into the next (afterClusterTime), so a secondary waits until it has applied up to that point.

Try it in the Replica set simulator: write with w:1, kill the primary before replication, and watch the write get rolled back.

Avoid / preferDo this, not that

Avoid
db.payments.insertOne(p, { writeConcern: { w: 1 } })
Prefer
db.payments.insertOne(p, { writeConcern: { w: "majority", j: true, wtimeout: 5000 } })

A w:1 write acknowledged by a primary that then fails over can be rolled back. Majority acknowledgement survives any single failure.

Avoid
db.orders.insertOne(o)
db.orders.find({ _id: o._id }).readPref("secondary")   // may return nothing
Prefer
const s = db.getMongo().startSession({ causalConsistency: true })
// writes with w:"majority", reads with readConcern "majority" in that session

A secondary may not have replicated your write yet. A causally consistent session guarantees you read your own writes even from secondaries.

PitfallsCommon mistakes

  • Using w: 0 or w: 1 for business-critical data.
  • Reading from secondaries to "scale reads" without accepting staleness; it also moves load rather than removing it.
  • Treating wtimeout as a rollback; the write may still complete later.
  • Arbiters in PSA topologies: with one data-bearing member down, majority writes cannot be acknowledged and the majority commit point stalls, increasing cache pressure.

LimitsWhen not to use it

In a PSA set with the secondary down, w: "majority" writes stall because the arbiter cannot acknowledge writes. readConcern: "linearizable" is slow and only meaningful for single-document reads on the primary. Secondary reads do not scale reads that need fresh data.

SecuritySecurity notes

Security events need durability too. A revoked token, a lockout counter or an audit record written with w:1 can vanish in a rollback, quietly undoing the revocation. Write them with w: "majority".

ChallengeTry it yourself

Insert a "token-revoked" event into a scratch collection with majority write concern, journaling and a 5-second timeout, then read it back with read concern majority.

Show one solution
One solution
db.audit_lab.drop()
db.audit_lab.insertOne({ event: "token-revoked", at: new Date() }, { writeConcern: { w: "majority", j: true, wtimeout: 5000 } })
db.audit_lab.find({}, { _id: 0, event: 1 }).readConcern("majority")

InterviewQuestions you should be able to answer

What happens to a w:1 write if the primary crashes right after acknowledging it?

If the write had not reached a secondary that becomes primary, the new primary does not have it. When the old primary rejoins it rolls back the write (saved to a rollback directory). The client got success, but the data is gone from the replica set. w: "majority" prevents this because a majority-acknowledged write is guaranteed to be on whichever member wins the election.

Explain read concern majority vs linearizable.

majority returns data acknowledged by a majority as of the node's majority-committed snapshot; it may not include the very latest majority writes (it can be slightly stale) but is never rolled back. linearizable additionally guarantees the read reflects all writes acknowledged before the read began, by confirming the node is still primary with a majority write; it works only on the primary for single-document reads and is slower.

How do you get read-your-own-writes on secondaries?

Use a causally consistent session with w: "majority" writes and readConcern: "majority" reads. The driver passes the operation time of the write as afterClusterTime to the secondary read, which waits until the secondary has replicated that far.

QuizCheck your understanding

4 questions with instant feedback in the interactive lesson; a wrong answer goes into your review deck.