MongoDB Internals
WiredTiger Storage Engine
graph TD
CLIENT3["MongoDB client"] --> MONGOD["mongod process"]
MONGOD --> WT["WiredTiger Storage Engine"]
subgraph WT["WiredTiger"]
CACHE3["WT Cache (wiredTigerCacheSizeGB)<br/>B-tree pages in memory<br/>Default: 50% of RAM - 1GB"]
JOURNAL["Journal (WAL)<br/>write-ahead log<br/>journal/ directory<br/>100ms sync interval"]
CHECKPOINT["Checkpoint<br/>every 60s or 2GB journal<br/>consistent snapshot on disk"]
end
WT --> DATA3["Collection files (.wt)<br/>B-tree pages<br/>snappy compressed by default"]
WT --> IDX3["Index files (.wt)<br/>B-tree on _id + user indexes"]
Document Model and BSON
MongoDB stores documents as BSON (Binary JSON):
BSON document: {_id: ObjectId("..."), name: "Alice", age: 30}
Binary encoding:
[doc_length 4B][type 1B][key "name\0"][value "Alice"][type 1B][key "age\0"][value 30 4B]...[terminator 0x00]
Advantages:
- Traversable without full parse (know field length from header)
- Native types: Date, ObjectId, Binary, Decimal128
- ObjectId: 12 bytes = 4B timestamp + 5B random + 3B counter (sortable, unique, no central seq)
Oplog — Replication Log
The oplog is a capped collection in the local database. Every write to the primary is recorded as an idempotent operation.
graph LR
PRIMARY3["Primary<br/>oplog: capped collection<br/>local.oplog.rs"] -->|"oplog tailing (change stream)"| S1_5["Secondary 1<br/>reads + applies oplog entries"]
PRIMARY3 --> S2_5["Secondary 2<br/>reads + applies oplog entries"]
subgraph "Oplog entry"
OP["{ ts: Timestamp, op: 'u',<br/> ns: 'db.users',<br/> o: {$set: {name: 'Bob'}},<br/> o2: {"_id: ObjectId('...')"} }"]
end
op types: i (insert), u (update), d (delete), c (command: createCollection, dropCollection), n (no-op, keepalive)
Oplog window: Capped at a fixed size (default 5% of disk space, min 1GB). If a secondary falls behind more than the oplog window, it needs a full resync.
Aggregation Pipeline
graph LR
COLL["orders collection"] --> MATCH
MATCH["$match<br/>{status: 'paid', date: {$gte: ...}}"] --> GROUP
GROUP["$group<br/>{_id: '$user_id', total: {$sum: '$amount'}}"] --> SORT
SORT["$sort<br/>{total: -1}"] --> LIMIT
LIMIT["$limit: 10"] --> OUT["Result: top 10 users by spend"]
MongoDB can use indexes in $match and $sort stages. explain() shows if indexes are used:
db.orders.aggregate([
{$match: {status: 'paid'}},
{$group: {_id: '$user_id', total: {$sum: '$amount'}}}
]).explain('executionStats')
Index Types
// Standard B-tree
db.users.createIndex({email: 1}) // ascending
db.users.createIndex({email: 1, status: 1}) // compound
db.users.createIndex({email: 1}, {unique: true}) // unique
// Partial index (only index active users — smaller, faster)
db.users.createIndex({email: 1}, {
partialFilterExpression: {deleted: {$exists: false}}
})
// TTL index (auto-delete documents after N seconds)
db.sessions.createIndex({createdAt: 1}, {expireAfterSeconds: 3600})
// Text index (full-text search)
db.posts.createIndex({body: 'text', title: 'text'})
db.posts.find({$text: {$search: "kubernetes failover"}})
// Geospatial
db.locations.createIndex({coords: '2dsphere'})
db.locations.find({coords: {$near: {$geometry: {type:'Point', coordinates:[77.2,28.6]}, $maxDistance: 1000}}})
Write Concern and Read Concern — Deep Dive
sequenceDiagram
participant APP4 as Application
participant PRI4 as Primary
participant SEC4 as Secondary
Note over APP4,SEC4: writeConcern: {w: "majority", j: true}
APP4->>PRI4: insert document
PRI4->>PRI4: write to journal (j:true = fsync)
PRI4->>SEC4: replicate via oplog
SEC4->>SEC4: write to journal + apply
SEC4-->>PRI4: acknowledge
Note over PRI4: Majority (2/3) confirmed
PRI4-->>APP4: WriteResult confirmed
Note over APP4,SEC4: readConcern: "majority"
APP4->>PRI4: find({_id: ...}) with majority read concern
PRI4->>PRI4: Only return data committed to majority
Note over PRI4: Won't return data that might be rolled back on failover
PRI4-->>APP4: Document (guaranteed stable)
| Write Concern | Data loss on failover | Latency |
|---|---|---|
{w:1} |
Yes (if only primary had it) | Lowest |
{w:"majority"} |
No | +replica RTT |
{w:"majority", j:true} |
No + disk durable | Highest |
explain() — Query Analysis
// Find execution plan
db.orders.find({user_id: "123", status: "paid"}).explain("executionStats")
// winningPlan.stage: "COLLSCAN" = full scan (bad) | "IXSCAN" = index (good)
// executionStats.totalDocsExamined vs totalDocsReturned: large ratio = missing index
// Create compound index
db.orders.createIndex({user_id: 1, status: 1})
// Covering index: all projected fields in index = no heap fetch
db.orders.createIndex({user_id: 1, status: 1, amount: 1})
db.orders.find({user_id: "123"}, {status:1, amount:1, _id:0})
// Extra: "Using index" — zero document reads
Transactions (4.0+)
const session = db.getMongo().startSession();
session.startTransaction({ readConcern:{level:"snapshot"}, writeConcern:{w:"majority"} });
try {
const accounts = session.getDatabase("bank").accounts;
accounts.updateOne({_id:"alice"}, {$inc:{balance:-100}}, {session});
accounts.updateOne({_id:"bob"}, {$inc:{balance: 100}}, {session});
session.commitTransaction();
} catch (err) {
session.abortTransaction();
throw err;
} finally { session.endSession(); }
Change Streams
Real-time feed of insert/update/delete events — built on the oplog.
const stream = db.orders.watch([
{$match: {"operationType": {$in:["insert","update"]}}},
{$match: {"fullDocument.status": "paid"}}
]);
stream.on("change", change => processOrder(change.fullDocument));
// Crash recovery: store resumeToken, restart from it
const stream2 = db.orders.watch([], {resumeAfter: lastToken});
Sharding
graph TD
APP["App"] --> MONGOS["mongos router"]
MONGOS --> CFG["Config servers<br/>(chunk map)"]
MONGOS --> S1["Shard 1 replica set<br/>user_id: 0-500K"]
MONGOS --> S2["Shard 2 replica set<br/>user_id: 500K-1M"]
sh.enableSharding("mydb")
sh.shardCollection("mydb.orders", {user_id: "hashed"})
// hashed = even distribution
// ranged = supports range queries but hotspot risk on monotonic keys
sh.getBalancerState() // check if auto-balancer is moving chunks
Aggregation Pipeline Stages
db.orders.aggregate([
{$match: {status:"paid", created_at:{$gte: new Date("2024-01-01")}}}, // filter early
{$lookup: {from:"users", localField:"user_id", foreignField:"_id", as:"user"}},
{$unwind: "$user"},
{$group: {_id:"$user_id", total:{$sum:"$amount"}, count:{$sum:1}}},
{$match: {total:{$gte:1000}}}, // post-group filter
{$sort: {total:-1}},
{$limit: 100},
{$project:{_id:0, user_id:"$_id", total:1, count:1}}
])
// allowDiskUse:true if pipeline > 100MB RAM
Monitoring
db.currentOp({secs_running:{$gt:5}}) // long-running ops
db.killOp(opid)
db.setProfilingLevel(1, {slowms:100}) // log slow queries
db.system.profile.find().sort({ts:-1}).limit(10)
rs.status() // replica set health + lag