How do you find and fix a slow query in MongoDB?
Find it first: operations slower than
slowms(100 ms by default) are written to the server log, the database profiler (db.setProfilingLevel(1)) stores them insystem.profile, and Atlas shows them in its Query Profiler. Then run the query withexplain('executionStats')and look forCOLLSCAN, an in-memorySORTstage, or far more documents examined than returned. Fix it with an index in ESR order, a smaller projection or a schema change.How does MongoDB choose a query plan?
When several indexes could serve a query, the planner runs the candidate plans in a short trial, picks the one that produces results with the least work, and caches it for that query shape. The cached plan is reevaluated if it starts doing much more work, and the cache is cleared when the collection's indexes change or the server restarts.
hint()forces an index, but the right index is better than a hint.What is write concern?
How many members must acknowledge a write before it counts as successful.
w: 1waits for the primary only, and the write can be rolled back if the primary fails before replicating it.w: 'majority'waits for a majority of voting members, so the write survives failover; it is the default since MongoDB 5.0.j: truealso waits for the on-disk journal, andwtimeoutlimits the wait.What is read concern?
Which data a read may return.
local(the default) returns the member's newest data, which may later be rolled back.majorityreturns only data acknowledged by a majority, so it can never be rolled back.linearizablealso guarantees the read reflects every majority write completed before it, andsnapshotreads one point in time, as transactions do. With majority reads and writes in a causally consistent session, a client always reads its own writes.What is read preference, and when should you read from secondaries?
It decides which member serves reads:
primary(the default),primaryPreferred,secondary,secondaryPreferredornearest(lowest latency). Secondaries replicate asynchronously, so their data can be stale: use them for analytics, reports or users far from the primary, not for reading what the user just wrote.maxStalenessSecondsskips secondaries that lag too far behind.What are change streams?
A way to subscribe to inserts, updates, deletes and other changes on a collection, a database or a whole deployment, with
watch(). They read the oplog, so they need a replica set or sharded cluster. Each event carries a resume token: store it and pass it asresumeAfterafter a restart to continue without missing events, as long as the oplog still holds them.const stream = orders.watch([{ $match: { operationType: 'insert' } }]); for await (const change of stream) { await saveToken(change._id); // the resume token console.log(change.fullDocument.total); }How should a Node.js app manage MongoDB connections?
Create one
MongoClientper process at startup and reuse it everywhere: it holds a connection pool (maxPoolSize, 100 by default) and monitors the cluster. A client per request adds a TCP and TLS handshake and authentication to every call, and can exhaust the server's connection limit. In serverless functions, create the client outside the handler so warm invocations reuse it, and keep the connection string in an environment variable.How does MongoDB use memory, and what is the working set?
The WiredTiger storage engine keeps its own cache, by default the larger of 50% of (RAM minus 1 GB) or 256 MB, and the rest of memory serves the operating system's file cache. The working set is the data and indexes your application touches regularly. If it fits in RAM, reads come from memory; if not, they go to disk and latency jumps. Watch cache eviction and keep indexes selective.
Can a MongoDB query be injected through JSON input?
Node.jsconst { MongoClient } = require('mongodb'); const client = new MongoClient('mongodb://localhost:27017'); async function main() { const users = client.db('app').collection('users'); await users.insertOne({ user: 'admin', password: 's3cret' }); // a login request body sent as JSON by an attacker const body = JSON.parse('{"user":"admin","password":{"$ne":null}}'); const found = await users.findOne({ user: body.user, password: body.password }); console.log(found ? `logged in as ${found.user}` : 'denied'); } main().finally(() => client.close());It prints
logged in as admin. The attacker sent an object,{ "$ne": null }, where a string was expected, and it became a query operator: any password that is not null matches. Check input types (typeof password === 'string') or reject keys that start with$, and never store or compare raw passwords. The SQL version of this bug is in preventing SQL injection.How do you stop two users from overwriting each other's edits?
Node.jsconst { MongoClient } = require('mongodb'); const client = new MongoClient('mongodb://localhost:27017'); async function main() { const docs = client.db('app').collection('docs'); const { insertedId } = await docs.insertOne({ text: 'v1', version: 1 }); const a = await docs.updateOne( { _id: insertedId, version: 1 }, { $set: { text: 'from A' }, $inc: { version: 1 } } ); const b = await docs.updateOne( { _id: insertedId, version: 1 }, { $set: { text: 'from B' }, $inc: { version: 1 } } ); const doc = await docs.findOne({ _id: insertedId }); console.log(a.modifiedCount, b.modifiedCount, doc.text, doc.version); } main().finally(() => client.close());It prints
1 0 from A 2. This is optimistic concurrency: each update puts the version it read in the filter and increments it. The first update matches and moves the version to 2, so the second, still expecting version 1, matches nothing, and the app can reload and retry instead of silently overwriting. Mongoose'soptimisticConcurrencyoption does the same with__v.How do you back up a MongoDB deployment?
mongodumpandmongorestoreexport BSON and suit small databases; on a replica set,--oplogmakes the dump a consistent point in time. For large deployments, use filesystem snapshots (with the journal on the same volume) or a managed backup such as Atlas cloud backups, which add point-in-time restore from the oplog. Restore regularly to test: an untested backup is a hope, not a plan.How do you change the schema of a large collection without downtime?
In steps that the running code tolerates. Add a
schemaVersionfield, deploy code that reads both the old and new shapes and writes the new one, then migrate old documents in small throttled batches in the background (ranges of_id). When none are left, remove the old read path. For rarely touched data, a lazy migration also works: rewrite each document the next time it is read or written.
Advanced MongoDB Interview Questions
Running MongoDB in production: slow queries, query plans, write and read concerns, change streams, connections, memory, security and safe concurrent updates.