MongoDB MCQs multiple-choice questions with answers & explanations
All 22 MongoDB quiz questions on one page. Pick an answer in your head, then open Show answer to check it and read why. Want a score and a timer? Take them as a quiz instead.
Official reference: MongoDB manual
- 1.mid
Which documents does the
find()return?db.scores.insertMany([ { _id: 1, results: [82, 85, 88] }, { _id: 2, results: [75, 88, 89] } ]); db.scores.find({ results: { $gte: 80, $lt: 85 } });- AOnly
_id: 1 - BOnly
_id: 2 - CBoth documents
- DNeither document
Show answer
Answer: C (Both documents)
Without
$elemMatch, each condition on an array can be satisfied by a different element. In_id: 2, 88 satisfies$gte: 80and 75 satisfies$lt: 85, so it matches too. To require one element between 80 and 85, use{ results: { $elemMatch: { $gte: 80, $lt: 85 } } }, which returns only_id: 1. - AOnly
- 2.easy
What do the first 4 bytes of an ObjectId contain?
- AA random value unique to the machine and process
- BA timestamp in seconds since the Unix epoch
- CA counter that increments per client process
- DA hash of the database and collection name
Show answer
Answer: B (A timestamp in seconds since the Unix epoch)
An ObjectId is 12 bytes: a 4-byte timestamp (seconds since the Unix epoch), a 5-byte random value generated once per process, and a 3-byte incrementing counter that starts at a random value. That is why
getTimestamp()can recover the creation time. - 3.mid
On MongoDB 5.0 or later, what is the implicit default write concern for a three-member replica set with no arbiters?
- A
{ w: "majority" } - B
{ w: 1 } - C
{ w: 0 } - D
{ w: 3, j: true }
Show answer
Answer: A (
{ w: "majority" })Since 5.0 the implicit default is
w: "majority". The exception is some arbiter setups: if the number of data-bearing voting members is not greater than the voting majority (for example primary-secondary-arbiter), the default becomes{ w: 1 }. - A
- 4.mid
Following the ESR guideline, which index best supports this query?
db.orders.find({ status: "A", qty: { $gt: 10 } }).sort({ date: -1 });- A
{ qty: 1, status: 1, date: -1 } - B
{ status: 1, qty: 1, date: -1 } - C
{ date: -1, qty: 1, status: 1 } - D
{ status: 1, date: -1, qty: 1 }
Show answer
Answer: D (
{ status: 1, date: -1, qty: 1 })ESR puts Equality fields first (
status), then the Sort field (date), then Range fields (qty). Putting the range onqtybeforedatewould leave the matching keys out ofdateorder and force an in-memory sort. - A
- 5.mid
With only the index
{ email: 1, name: 1 }(plus the default_idindex), which query is covered?- A
db.users.find({ email: "a@x.io" }, { name: 1 }) - B
db.users.find({ email: "a@x.io" }, { _id: 0, name: 1, age: 1 }) - C
db.users.find({ email: null }, { _id: 0, name: 1 }) - D
db.users.find({ email: "a@x.io" }, { _id: 0, name: 1 })
Show answer
Answer: D (
db.users.find({ email: "a@x.io" }, { _id: 0, name: 1 }))A covered query needs every filtered and returned field in one index. The first option also returns
_id, which is not in the index; the second returnsage; and a filter comparing a field tonullcannot be covered. Excluding_idand returning only indexed fields lets MongoDB skip the FETCH stage. - A
- 6.mid
No document matches the filter. Apart from
_id, which document does this upsert insert?db.inventory.updateOne( { sku: "X1", qty: { $lt: 5 } }, { $set: { status: "low" }, $setOnInsert: { createdBy: "job" } }, { upsert: true } );- A
{ sku: "X1", qty: { $lt: 5 }, status: "low", createdBy: "job" } - B
{ sku: "X1", status: "low", createdBy: "job" } - C
{ sku: "X1", status: "low" } - D
{ status: "low", createdBy: "job" }
Show answer
Answer: B (
{ sku: "X1", status: "low", createdBy: "job" })An upsert builds the new document from the equality conditions in the filter (
sku), then applies the update operators, including$setOnInsert, which runs only on insert. Comparison conditions such asqty: { $lt: 5 }are not copied into the new document. - A
- 7.easy
How often does the background task that removes expired documents from TTL indexes run?
- AThe instant each document expires
- BOnce every hour, on the hour
- CEvery 60 seconds
- DWhenever the collection is queried
Show answer
Answer: C (Every 60 seconds)
The TTL monitor runs every 60 seconds, so documents can remain for a while after they expire, longer under heavy load. If expired data must never be visible, also filter on the date field in your queries.
- 8.mid
A collection has
createIndex({ email: 1 }, { unique: true }). What happens when you insert two documents that have noemailfield?- AThe second insert fails with a duplicate key error
- BBoth succeed because missing fields are not indexed
- CBoth fail because a unique field becomes required
- DMongoDB converts the index to a sparse index
Show answer
Answer: A (The second insert fails with a duplicate key error)
A unique index stores a
nullkey for documents missing the field, and only one document can hold that null. To allow many documents without an email, use a partial unique index withpartialFilterExpression: { email: { $exists: true } }. - 9.easy
The document is
{ _id: 1, tags: ["a"] }. What istagsafter this update?db.posts.updateOne({ _id: 1 }, { $push: { tags: ["b", "c"] } });- A
["a", "b", "c"] - B
["b", "c"] - C
["a", ["b", "c"]] - D
["a", ["b"], ["c"]]
Show answer
Answer: C (
["a", ["b", "c"]])$pushappends its value as a single element, so pushing an array nests it. To append each value separately, use{ $push: { tags: { $each: ["b", "c"] } } }. - A
- 10.easy
The document is
{ _id: 1, tags: ["a", "b"] }. What istagsafter this update?db.posts.updateOne({ _id: 1 }, { $addToSet: { tags: { $each: ["b", "c"] } } });- A
["a", "b", "b", "c"] - B
["a", "b", ["b", "c"]] - C
["b", "c"] - D
["a", "b", "c"]
Show answer
Answer: D (
["a", "b", "c"])$addToSetadds a value only if it is not already in the array, and$eachapplies that to every listed value. "b" is already present, so only "c" is added. Without$each, the whole array["b", "c"]would be added as one element. - A
- 11.easy
What is the default read preference for a replica set connection?
- A
nearest - B
primary - C
secondaryPreferred - D
primaryPreferred
Show answer
Answer: B (
primary)By default all reads go to the primary, and they fail if no primary is available.
primaryPreferredfalls back to secondaries during failover, whilesecondaryPreferredandnearestaccept possibly stale data from secondaries. - A
- 12.mid
The
orderscollection has an index on{ total: 1 }. Can the$matchin this pipeline use it?db.orders.aggregate([ { $group: { _id: "$customerId", total: { $sum: "$amount" } } }, { $match: { total: { $gt: 1000 } } } ]);- AYes, the optimizer moves the
$matchahead of$group - BYes, a
$matchcan use indexes wherever it appears - CNo, this
totalonly exists after$groupruns - DOnly when the pipeline runs with
allowDiskUse: true
Show answer
Answer: C (No, this
totalonly exists after$groupruns)Here
totalis computed by$group, so the$matchfilters grouped results in memory and no collection index applies. Only stages at the start of a pipeline read from the collection with indexes. The optimizer only moves a$matchearlier when it does not depend on computed fields. - AYes, the optimizer moves the
- 13.easy
Which deployment does not support multi-document transactions?
- AA three-member replica set
- BA sharded cluster running 4.2 or later
- CA five-member replica set
- DA standalone
mongodserver
Show answer
Answer: D (A standalone
mongodserver)Multi-document transactions need a replica set (since 4.0) or a sharded cluster (since 4.2). A standalone server does not support them. You can convert a standalone into a single-member replica set for development.
- 14.mid
You shard an
eventscollection on the ranged key{ createdAt: 1 }. What is the main problem?- AEvery new insert lands in the chunk holding the highest values
- BQueries filtering on a time range must be sent to every shard
- CA shard key on a date field cannot be backed by an index
- DDocuments that lack
createdAtare always rejected bymongos
Show answer
Answer: A (Every new insert lands in the chunk holding the highest values)
With an always-increasing key, all new documents fall into the chunk whose upper bound is
maxKey, so one shard takes every insert. Ranged keys actually keep time-range queries targeted. Hashed sharding or a compound key such as{ deviceId: 1, createdAt: 1 }spreads the writes. - 15.mid
Why does
find().sort({ createdAt: -1 }).skip(100000).limit(20)get slow even with an index oncreatedAt?- A
skip()stops the query planner from using any index - B
limit()runs beforeskip()and discards the results - CThe server still walks past all 100,000 skipped entries
- DThe driver downloads every skipped document to the client
Show answer
Answer: C (The server still walks past all 100,000 skipped entries)
The index supplies the order, but the server still has to step over every skipped entry, so cost grows with page depth. Range-based pagination, filtering on values after the last
createdAtand_idseen, turns each page into an index seek. - A
- 16.easy
The winning plan in
explain()output has aCOLLSCANstage. What does that mean?- AThe query was answered entirely from an index
- BThe query read every document in the collection
- CThe query was broadcast to every shard in the cluster
- DThe query used a compound index on several fields
Show answer
Answer: B (The query read every document in the collection)
COLLSCANis a full collection scan: no index was used to narrow the search. An index-backed plan showsIXSCAN, usually followed byFETCH; a covered query has noFETCHand examines zero documents. - 17.mid
An order has a
customerIdwith no matching customer. What happens to it in this pipeline?db.orders.aggregate([ { $lookup: { from: "customers", localField: "customerId", foreignField: "_id", as: "customer" } }, { $unwind: "$customer" } ]);- AIt is dropped from the output
- BIt is output with
customer: null - CIt is output with
customer: [] - DThe whole pipeline fails with an error
Show answer
Answer: A (It is dropped from the output)
$lookupis a left outer join, so the order first getscustomer: [].$unwindthen outputs nothing for an empty array, so the order disappears. Use{ $unwind: { path: "$customer", preserveNullAndEmptyArrays: true } }to keep it. - 18.hard
The collection has the index
{ tags: 1, sizes: 1 }. What happens when you insert this document?db.products.insertOne({ tags: ["sale", "new"], sizes: ["S", "M"] });- AIt succeeds and creates four index keys
- BIt succeeds, but only
tagsis indexed - CIt succeeds and the index becomes hidden
- DIt fails: two indexed fields are arrays
Show answer
Answer: D (It fails: two indexed fields are arrays)
In a compound multikey index, each document can have at most one indexed field whose value is an array. Once the index exists, inserting a document where both
tagsandsizesare arrays is rejected. - 19.hard
What does
validationLevel: "moderate"do for a collection with a$jsonSchemavalidator?- AUpdates to already-invalid documents skip validation
- BInvalid writes are accepted, and each violation is logged
- CRules are checked on inserts only and never on updates
- DRules are checked by a background job instead of on writes
Show answer
Answer: A (Updates to already-invalid documents skip validation)
With
moderate, inserts and updates to currently valid documents are validated, but updates to existing documents that do not match the rules are not required to pass. Accepting invalid writes and logging them isvalidationAction: "warn", a separate setting. The default level isstrict. - 20.easy
In mongosh, what does
db.jobs.findOneAndUpdate(filter, update)return by default?- AAn object with
matchedCountandmodifiedCount - BThe matched document as it was before the update
- CThe matched document after the update was applied
- DOnly the
_idof the document it modified
Show answer
Answer: B (The matched document as it was before the update)
It returns the original document by default. Pass
returnDocument: "after"(orreturnNewDocument: true) to get the updated version.updateOneis the method that returns counts such asmatchedCountandmodifiedCount. - AAn object with
- 21.hard
The
userscollection is sharded on{ userId: "hashed" }. Which query canmongosroute to a single shard?- A
db.users.find({ userId: { $gt: 40, $lt: 50 } }) - B
db.users.find({ email: "a@x.io" }) - C
db.users.find({ userId: 42 }) - D
db.users.find({}).sort({ userId: 1 })
Show answer
Answer: C (
db.users.find({ userId: 42 }))An equality match on a hashed shard key can be hashed and targeted to one shard. Range queries on the key become broadcast, because nearby values are scattered by the hash, and queries without the shard key are scatter-gather.
- A
- 22.hard
A write with
{ w: "majority", wtimeout: 5000 }returns a write concern timeout error. What can you conclude about the write?- AIt was rolled back on every member of the set
- BIt may be applied and could still replicate
- CIt was never applied on the primary at all
- DThe server queues it and retries automatically
Show answer
Answer: B (It may be applied and could still replicate)
wtimeoutonly limits how long the client waits for acknowledgment. MongoDB does not undo modifications that succeeded before the timeout, and the write may still reach a majority later, so retries must be idempotent.