MongoDB — Practical
MongoDB — Practical patterns
Section titled “MongoDB — Practical patterns”Connection & pooling (Node, native driver)
Section titled “Connection & pooling (Node, native driver)”import { MongoClient } from 'mongodb';
const client = new MongoClient(process.env.MONGO_URL!, { maxPoolSize: 50, minPoolSize: 5, serverSelectionTimeoutMS: 5000, retryWrites: true,});await client.connect();const db = client.db('app');Indexes (idempotent)
Section titled “Indexes (idempotent)”db.users.createIndex({ email: 1 }, { unique: true })db.users.createIndex({ status: 1, createdAt: -1 })db.sessions.createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 })db.posts.createIndex({ tags: 1 }) // multikeydb.posts.createIndex({ body: 'text' })db.places.createIndex({ loc: '2dsphere' })
// partial — only index docs matching filterdb.orders.createIndex( { customerId: 1 }, { partialFilterExpression: { status: { $in: ['paid','shipped'] } } })Aggregation: top buyers
Section titled “Aggregation: top buyers”db.orders.aggregate([ { $match: { status: 'paid', createdAt: { $gte: ISODate('2026-01-01') } } }, { $group: { _id: '$userId', total: { $sum: '$amount' }, n: { $sum: 1 } } }, { $sort: { total: -1 } }, { $limit: 10 }, { $lookup: { from: 'users', localField: '_id', foreignField: '_id', as: 'user' } }, { $unwind: '$user' }, { $project: { _id: 0, name: '$user.name', total: 1, n: 1 } }])Keyset pagination
Section titled “Keyset pagination”// page 1db.posts.find({}) .sort({ createdAt: -1, _id: -1 }) .limit(50);
// next page (lastCreatedAt, lastId from previous page)db.posts.find({ $or: [ { createdAt: { $lt: lastCreatedAt } }, { createdAt: lastCreatedAt, _id: { $lt: lastId } } ]}).sort({ createdAt: -1, _id: -1 }).limit(50);Atomic update with $set + condition (optimistic concurrency)
Section titled “Atomic update with $set + condition (optimistic concurrency)”db.docs.updateOne( { _id, version: 5 }, { $set: { title: 'new', updatedAt: new Date() }, $inc: { version: 1 } });// matchedCount=0 → conflict, retryBulk write
Section titled “Bulk write”db.users.bulkWrite([ { insertOne: { document: { _id: 1, n: 'A' } } }, { updateOne: { filter: { _id: 2 }, update: { $set: { n: 'B' } }, upsert: true } }, { deleteOne: { filter: { _id: 3 } } },], { ordered: false });Multi-doc transaction
Section titled “Multi-doc transaction”const session = client.startSession();try { await session.withTransaction(async () => { await db.collection('accounts').updateOne( { _id: from }, { $inc: { balance: -amount } }, { session }); await db.collection('accounts').updateOne( { _id: to }, { $inc: { balance: amount } }, { session }); }, { writeConcern: { w: 'majority' } });} finally { await session.endSession();}Schema validation
Section titled “Schema validation”db.createCollection('users', { validator: { $jsonSchema: { bsonType: 'object', required: ['email', 'createdAt'], properties: { email: { bsonType: 'string', pattern: '^.+@.+$' }, age: { bsonType: 'int', minimum: 0, maximum: 150 }, } } }});EXPLAIN
Section titled “EXPLAIN”db.users.find({ email: 'a@b.com' }).explain('executionStats')// look at: stage (IXSCAN good, COLLSCAN bad), nReturned vs totalDocsExaminedChange streams (CDC)
Section titled “Change streams (CDC)”const stream = db.collection('orders').watch([ { $match: { 'fullDocument.status': 'paid' } }], { fullDocument: 'updateLookup' });for await (const ev of stream) { console.log(ev.operationType, ev.fullDocument);}Time-series collection (5.0+)
Section titled “Time-series collection (5.0+)”db.createCollection('metrics', { timeseries: { timeField: 'ts', metaField: 'host', granularity: 'seconds' }, expireAfterSeconds: 60 * 60 * 24 * 30});Geospatial query
Section titled “Geospatial query”db.places.find({ loc: { $near: { $geometry: { type:'Point', coordinates:[55.27, 25.20] }, $maxDistance: 1000 } }});Useful diagnostics
Section titled “Useful diagnostics”db.serverStatus()db.currentOp({ secs_running: { $gt: 1 } })db.killOp(opId)db.coll.getIndexes()db.coll.totalIndexSize()db.coll.stats()Production tips
Section titled “Production tips”- Always
w: 'majority'for writes that matter. - TTL index for expiring sessions/tokens — reaper runs every 60s, not exact.
- Don’t sort without index → in-memory limit 100MB → error.
- Avoid
$whereand JS$function— slow, can’t use indexes. - Watch for unbounded arrays in documents — eventually hit 16MB cap.
Deep — ACID transaction (callback API)
Section titled “Deep — ACID transaction (callback API)”const session = client.startSession();const opts = { readConcern: { level: 'snapshot' }, writeConcern: { w: 'majority' }, readPreference: 'primary'};try { await session.withTransaction(async () => { await accounts.updateOne({ _id: 'A' }, { $inc: { bal: -100 } }, { session }); await accounts.updateOne({ _id: 'B' }, { $inc: { bal: 100 } }, { session }); }, opts);} finally { await session.endSession(); }Deep — ESR compound index
Section titled “Deep — ESR compound index”// Query: equality on directors, sort by year, range on runtimedb.movies.find( { directors: "David Lynch", runtime: { $lt: 130 } }).sort({ year: 1 });
// ESR-correct compound indexdb.movies.createIndex({ directors: 1, year: 1, runtime: 1 });
// Verify: should show IXSCAN, no SORT stage, no FETCH-then-filterdb.movies.find({ directors: "David Lynch", runtime: { $lt: 130 } }) .sort({ year: 1 }) .explain("executionStats");// Look for: winningPlan.stage = "IXSCAN", no "SORT", totalKeysExamined ~ nReturned
// Hashed shard key — distributes monotonic _id evenlysh.shardCollection("app.events", { deviceId: "hashed" });Deep — aggregation with $lookup + inner pipeline
Section titled “Deep — aggregation with $lookup + inner pipeline”// Top 10 active customers in Q1 with their order totalsdb.customers.aggregate([ { $match: { status: "active", region: "AE" } }, // index! { $lookup: { from: "orders", let: { cid: "$_id" }, pipeline: [ { $match: { $expr: { $eq: ["$customerId", "$$cid"] }, createdAt: { $gte: ISODate("2026-01-01"), $lt: ISODate("2026-04-01") } } }, { $group: { _id: null, total: { $sum: "$amount" } } } ], as: "q1" }}, { $unwind: { path: "$q1", preserveNullAndEmptyArrays: true } }, { $sort: { "q1.total": -1 } }, { $limit: 10 }, { $project: { name: 1, total: { $ifNull: ["$q1.total", 0] } } }], { allowDiskUse: true });
// REQUIRED: index on the foreign collection's join field + filtersdb.orders.createIndex({ customerId: 1, createdAt: 1 });Deep — sharding compound + hashed
Section titled “Deep — sharding compound + hashed”// Hashed shard key avoids hot shards on monotonic IDssh.enableSharding("app");sh.shardCollection("app.events", { deviceId: "hashed" });
// Compound shard key combining locality + cardinality (better for range scans)sh.shardCollection("app.telemetry", { region: 1, deviceId: 1 });Deep — profiler + explain
Section titled “Deep — profiler + explain”// Capture slow ops above 100msdb.setProfilingLevel(1, { slowms: 100 });db.system.profile.find({ millis: { $gt: 100 } }) .sort({ ts: -1 }).limit(20);
// Inspect plandb.orders.find({ tenantId: 42, status: "open" }) .sort({ createdAt: -1 }) .explain("executionStats");// Bad signs: COLLSCAN, totalDocsExamined >> nReturned, SORT stage presentNote:
explain("executionStats")actually runs the query (and any writes); useexplain("queryPlanner")for safe inspection.