Back to Interview PrepGet interview ready with AILearn each topic the way interviewers ask it, then answer like you would in the interview.

Chapter 13 of 13

Top 45 MongoDB Interview Questions

Documents and collections, CRUD operations, query operators, schema design, indexes, aggregation, and Mongoose - organized by topic and difficulty, with explanations that go beyond a one-line definition and a code example for each one. Search or filter to find what you need, and share a direct link to any question.

Level:

Showing 45 of 45 questions

Questions reviewed0/45 · 0%

The first 15 of 45 questions are free to read. Sign up free to unlock every answer and track your progress.

Unlock all 45

MongoDB is a document-oriented NoSQL database that stores data as flexible, JSON-like documents (backed by BSON) rather than rows in fixed tables. Unlike a relational database, it does not require every record in a collection to share the same fields, and it favors embedding related data within a single document over enforcing joins across many tables. A common mistake is assuming MongoDB has no structure at all - most applications still design an implicit schema, they just enforce it in the application layer or through optional validation rules instead of the database engine.

Example

db.users.insertOne({ name: "Ada", email: "ada@example.com" })
db.users.insertOne({ name: "Alan", email: "alan@example.com", roles: ["admin"] })
// Both documents coexist fine in the same collection

BSON (Binary JSON) is the binary-encoded format MongoDB actually stores and transmits documents in. It extends JSON with additional types plain JSON lacks - a proper Date, a 64-bit integer, Decimal128, and ObjectId - and its binary encoding is faster to parse and traverse than text-based JSON. A common mistake is assuming documents are literally stored as JSON text; mongosh only displays them in a JSON-like syntax for readability.

A collection is a named group of documents, roughly analogous to a table, but it does not require every document to have the same fields or types by default. This flexible schema is a deliberate design choice that lets applications evolve document shapes without a migration step, though most teams still add validation rules or ODM-level schemas to avoid accidental inconsistency. A common mistake is treating "flexible schema" as "no schema at all" and designing without any consistent shape in mind.

Every document requires a unique "_id" field acting as its primary key within the collection. If none is supplied, MongoDB auto-generates a 12-byte ObjectId encoding a timestamp, a machine/process identifier, and an incrementing counter, guaranteeing uniqueness without central coordination. A common mistake is assuming "_id" can be changed after insertion - it is immutable, so correcting it requires deleting and re-inserting the document.

Example

db.users.insertOne({ name: "Grace" })
// _id auto-assigned, e.g. ObjectId("64f1c2a5e4b0a1b2c3d4e5f6")

db.users.insertOne({ _id: "grace@example.com", name: "Grace" })
// custom _id used instead

MongoDB tends to be a weaker fit for heavily relational data that requires constant cross-entity queries under strict consistency, such as a double-entry accounting ledger, since relational databases have decades of mature tooling built specifically for enforced constraints and transactional joins. It is also less ideal when your access patterns are unpredictable ad-hoc reporting across many normalized entities. A common mistake is forcing a document model onto data that is fundamentally tabular and highly interrelated just because MongoDB is trendy or already in the stack.

mongosh is the modern MongoDB shell, a JavaScript REPL that connects directly to a MongoDB server so you can run commands, inspect data, and prototype queries interactively before writing application code. Commands like db.collection.find() are actual JavaScript method calls evaluated in that REPL, not a separate query language. A common mistake is writing complex application logic entirely inside mongosh instead of using it for exploration and quick fixes, then implementing the real logic in the driver or an ODM.

insertOne() adds a single document and returns its acknowledgment (including the generated or supplied "_id"), while insertMany() inserts an array of documents in a single round trip, which is far more efficient than looping insertOne() calls for bulk data. A common mistake is inserting large batches one document at a time, which multiplies network overhead unnecessarily.

Example

db.users.insertMany([
  { name: "Grace", age: 45 },
  { name: "Alan", age: 41 }
])

find() returns a cursor over every document matching the filter, which you typically iterate or convert with .toArray(), while findOne() returns just the first matching document (or null) directly, without a cursor. A common mistake is calling find() when only a single expected result is needed, adding unnecessary cursor handling to the code.

Example

db.users.find({ age: { $gte: 30 } }).toArray()
db.users.findOne({ email: "ada@example.com" })

$set changes or adds only the fields you specify inside the update object, leaving every other field on the document untouched. Passing a plain object without any operators to updateOne(), by contrast, replaces the entire matched document with that object. A common mistake is forgetting $set and unintentionally wiping out fields that were not included in the update payload.

Example

db.users.updateOne({ name: "Ada" }, { $set: { age: 31 } })
// only "age" changes; all other fields remain untouched

Passing { upsert: true } tells MongoDB to insert a new document (built from the filter and update) if no document matches the filter, instead of doing nothing. It is commonly used for settings-style or counter-style documents keyed by an identifier, where you want "create if missing, update if present" in a single atomic call. A common mistake is relying on upsert with a loosely-specified filter, which can accidentally create duplicate near-identical documents if the filter does not uniquely identify the intended record.

Example

db.settings.updateOne(
  { userId: "u1" },
  { $set: { theme: "dark" } },
  { upsert: true }
)

deleteOne() removes only the first document matching the filter, while deleteMany() removes every matching document. Passing an empty filter object {} to deleteMany() matches every document in the collection, deleting everything in it - a command worth double-checking before running against production data. A common mistake is assuming an empty filter means "match nothing" when it actually means "match everything."

bulkWrite() accepts an array of operation descriptors (insertOne, updateOne, updateMany, deleteOne, replaceOne, etc.) and executes them together, either ordered (stopping at the first error) or unordered (continuing past failures), which is far more efficient than issuing each operation as a separate network call. A common mistake is not understanding ordered vs. unordered semantics - an ordered bulk write halts on the first failure, potentially leaving only some operations applied, while unordered continues and reports all failures together at the end.

Example

db.products.bulkWrite([
  { insertOne: { document: { name: "Mouse", price: 20 } } },
  { updateOne: { filter: { name: "Keyboard" }, update: { $set: { price: 45 } } } },
  { deleteOne: { filter: { name: "Old Item" } } }
])

$gt and $lt filter documents where a field is greater than or less than a given value (with $gte/$lte for inclusive bounds), while $in matches documents where the field equals any value in a supplied array. A common mistake is trying to check array membership with a plain equality comparison, which only matches an exact full-array value rather than "any of these values."

Example

db.products.find({ price: { $gt: 10, $lt: 50 } })
db.products.find({ category: { $in: ["books", "toys"] } })

$exists checks whether a field is present (or, with $exists: false, absent) on a document at all, independent of its value - which is especially useful given MongoDB's flexible schema, where not every document in a collection necessarily has every field. A common mistake is confusing $exists: true with checking for a non-null value; a field explicitly set to null still satisfies $exists: true.

Example

db.users.find({ phone: { $exists: true } })

$or and $nor take an array of conditions and match documents satisfying at least one, or none, of them respectively. $and also takes an array of conditions requiring all to match, but MongoDB already implicitly ANDs separate top-level fields in a filter object, so explicit $and is mainly needed when repeating conditions on the same field name or nesting logical operators. A common mistake is wrapping every query in $and unnecessarily when a plain multi-field filter object would already express the same logic more simply.

Example

db.products.find({
  $or: [{ category: "electronics" }, { price: { $lt: 20 } }]
})
16.What is the difference between $all and $elemMatch when querying arrays?17.How would you query for documents where a nested array field contains a specific object shape, and what indexing consideration applies?18.What does it mean to "design for your queries" in MongoDB?19.What is denormalization in MongoDB and what tradeoff does it involve?20.What is the Attribute Pattern and what problem does it solve?21.What is the Bucket Pattern and when should you use it?22.How do you decide between embedding and referencing for a one-to-many relationship?23.What is an index and why does it matter for query performance?24.What is the "prefix rule" for compound indexes?25.How do you use explain() to diagnose a slow query?26.What is the tradeoff of adding many indexes to a collection?27.What is a covered query and why is it especially fast?28.What is the aggregation pipeline, conceptually?29.Why should $match usually appear as early as possible in a pipeline?30.What does the $group stage do, and what does its "_id" field represent?31.What does $lookup do and when do you need it?32.How can you compute a percentage or ratio of a total using the aggregation framework?33.What is Mongoose and what problem does it solve?34.What is the difference between a Mongoose Schema and a Model?35.When does Mongoose validation run, and what happens on failure?36.What does .populate() do, and what is its performance implication?37.How should a Mongoose connection be managed in an Express application, and why?38.Is a write to a single MongoDB document atomic by default?39.When do you actually need a multi-document transaction?40.What role does a session play in a MongoDB transaction?41.What is the performance tradeoff of using transactions, and what alternative should be considered first?42.What is a replica set and what problem does it solve?43.What is sharding and what specific problem does it solve that replication does not?44.Why is choosing a good shard key so important, and what makes a shard key poor?45.What are three concrete best practices for keeping a MongoDB deployment healthy as it scales?
You're viewing a free lesson. Sign up free to track your progress and unlock the full course.Sign up freeSign in