Articles · MongoDB
MongoDB Aggregation Interview Questions: Pipelines, Lookups, and Memory Limits
Practice MongoDB aggregation interviews with pipeline examples, lookup fan-out, missing matches, stage ordering, memory limits, and explain-plan checks.
MongoDB aggregation interview questions ask whether you can preserve the meaning of a result while documents change shape. The hardest mistakes are often not invalid syntax. They are a revenue total doubled by a lookup, an order silently removed by unwind, or a sort that becomes expensive only on realistic data.
Start every answer by naming the output grain: one document per order, customer, or day. Then trace how each pipeline stage changes that grain, its cardinality, and the amount of work remaining. This guide develops an original orders example and uses current MongoDB documentation for the engine rules. Deployment version and configuration still govern your actual system.
Here, the focus is narrower: constructing, debugging, and explaining aggregation pipelines under follow-up constraints.
What should I clarify before building a pipeline?
Ask what a returned document represents, which records qualify, and how missing relationships should behave. "Total spending by customer" leaves important questions unanswered: paid orders only or all orders? Refunds subtracted? One currency or several? Customers with zero spending included?
Use integer minor units for this exercise. Each order has an _id, customerId, status, amountCents, and createdAt. The requested output is the top two customers by total paid-order amount, with a deterministic customer-ID tie-break. Amounts are nonnegative integers in one currency; refunds are outside this particular contract.
The small dataset is deliberately inspectable:
| Order | Customer | Status | Amount in cents |
|---|---|---|---|
| O1 | A | paid | 4000 |
| O2 | A | paid | 2500 |
| O3 | B | paid | 9000 |
| O4 | B | pending | 8000 |
| O5 | C | paid | 6500 |
The correct totals are B: 9000, A: 6500, and C: 6500. With customer ID ascending as the secondary sort, the top two are B and A. State this expected result before writing code. It becomes a reference for every later optimization.
How do match, group, sort, and limit fit together?
An initial pipeline for the contract is straightforward:
db.orders.aggregate([
{ $match: { status: "paid" } },
{ $group: {
_id: "$customerId",
totalCents: { $sum: "$amountCents" },
orderCount: { $sum: 1 }
} },
{ $sort: { totalCents: -1, _id: 1 } },
{ $limit: 2 }
])
After match, four orders remain. After group, there are three customer documents. Sort establishes the required ranking; limit keeps two. The output no longer contains an individual order's status or timestamp because grouping created a different document shape.
Moving limit before group would answer a different question: spending among an arbitrary subset of input orders. Moving the paid-status match after group would fail because the grouped documents no longer carry that field. Optimization must preserve semantics, not just make intermediate counts smaller.
Ask about invalid amounts too. Missing values, strings, and mixed numeric types should be governed by a data contract or explicit validation policy. Do not let accidental accumulator behavior decide whether a corrupt order is silently ignored, rejected, or reported separately.
What is the difference between project and group?
$project reshapes individual documents; $group combines documents by a grouping key. A projection can calculate a line total for each input record without producing a customer-level total. A group with _id: "$customerId" changes the output grain to one document per customer.
An interviewer may show a projection containing a sum expression and ask whether it aggregates the whole collection. Do not infer behavior from the word "sum" alone. Operators have stage-specific contexts. Explain the current input document and the exact expression being evaluated.
Use a tiny counterexample: two orders for A should produce one customer total only after a grouping operation. If two documents still emerge, your pipeline has not produced the requested grain.
Early projections can improve clarity, but MongoDB can perform field-dependency optimizations itself. Do not promise a speedup just because you manually removed fields. Measure a representative pipeline, and distinguish explanatory style from an engine-level optimization supported by evidence.
Why does lookup sometimes double revenue?
$lookup adds matching foreign documents as an array. A subsequent $unwind emits a document per array element. If one order matches two foreign records, its amount appears twice after unwinding. A later sum can therefore count the same business event multiple times.
Suppose customer A accidentally has two matching profile records, while B and C each have one. The four paid orders become six documents after lookup and unwind: O1 and O2 each appear twice. Grouping amounts now reports A as 13000 instead of 6500. The query runs successfully and the answer is wrong.
This is why "lookup is like a join" is only a starting explanation. State the relationship cardinality and the integrity constraint. If the foreign key should be unique, verify the actual schema and enforce that rule where appropriate. A plain lookup does not make duplicate records disappear.
A useful diagnostic projection keeps the order ID and the number of matches. Investigate zero, one, and multiple matches separately before aggregating away the evidence. Do not hide an unexpected duplicate with $first until the business rule explicitly defines which record wins.
Should lookup happen before or after group?
Choose from the requested output. In our example, customer profile fields do not affect paid-order eligibility or spending. Grouping orders first can reduce the number of customer lookups. It also prevents a later profile unwind from multiplying the inputs to the already-computed sum.
{ $lookup: {
from: "customers",
localField: "_id",
foreignField: "_id",
as: "customer"
} }
This stage assumes grouped customer IDs match unique customer _id values. That assumption is different from joining on an unconstrained external customer code. Name it explicitly.
Now change the requirement: only customers whose current region is West qualify for ranking. Limiting to the top two before applying that region filter can return too few customers and miss the true top two eligible customers. The profile condition must be applied before the final ranking limit, even if a later join looked faster in the first version.
For correlated lookup pipelines, explain which values come from the outer document and how the foreign predicate is evaluated. Index eligibility depends on the form of comparisons and documented restrictions. Do not claim every $expr predicate can use every index. Inspect the actual plan for the deployed version.
How do missing matches and unwind options affect results?
By default, unwinding an empty lookup array does not preserve an output document for that input. If the contract requires orders with missing customers to remain visible, consider preserveNullAndEmptyArrays and a clear representation for the missing relationship.
There are two legitimate reports: "revenue attributable to known customer profiles" and "all paid revenue, including unresolved customers." They are not interchangeable. Removing unmatched orders might be correct for the first and a serious accounting mistake for the second.
Test three customers: one with exactly one profile, one with no profile, and one with duplicate profile matches through a nonunique field. Write expected row counts after every stage. This catches more bugs than running a large random dataset and checking whether the output looks plausible.
Also separate a missing field from an explicit null when the domain distinguishes them. Schema variation can affect matching and grouping. If all malformed customer IDs collapse into one group, the total may look like a legitimate high-spending customer unless you label or reject that bucket.
What do MongoDB aggregation memory limits mean?
MongoDB documents a 100 MB memory threshold for certain pipeline stages, with disk-spill behavior controlled by allowDiskUseByDefault and command options in supported versions. Since MongoDB 6.0, that server setting controls the default. It is not a statement that the entire pipeline has one universal 100 MB budget.
Nor does enabling disk use remove all constraints. Returned BSON documents still have a 16 MiB size limit. Some stages have special rules, including $facet; consult the specific stage documentation. A huge array accumulated into one result can fail even when spilling is allowed elsewhere.
An interview answer should identify the shape that grows. Does a group keep one number per customer, or push every order into an array? Does a sort handle ten records after grouping, or millions of raw events? Those choices can matter more than flipping one option.
For our spending report, retain the total and count rather than every original order unless the requested output needs them. If a detail view needs individual orders, a separately paginated query may be a clearer contract than embedding unlimited history in each customer document.
How do I explain a slow pipeline with evidence?
Use representative data and an explain plan appropriate to the deployment. A tiny fixture proves semantics but says little about production-scale cost. Execution statistics may perform substantial work, so use a safe environment or an approved diagnostic window.
Compare documents examined, keys examined, returned cardinality, blocking stages, and evidence of disk use where available. A large number of examined documents is not automatically a missing-index bug if the requested computation genuinely needs most records. Connect the work to the predicate and output.
For a date-bounded paid-order report, consider the leading filter and candidate indexes. An index supporting the initial status/date predicate may reduce input. It cannot automatically supply ordering by a total that is only computed after grouping. Explain that separation.
MongoDB can reorder eligible matches and coalesce some sort/limit patterns. Do not depend on the visual order of your source pipeline to predict every physical operation. Read the optimized plan, then validate that any manual rewrite preserves the exact fixture result, including ties and missing relationships.
Which follow-up questions should I rehearse?
How do you make top-customer results deterministic? Include a stable secondary sort key after the aggregate value. A tie is a data case, not an excuse for inconsistent pagination.
Can you limit before sorting? Only if a separate guarantee makes the retained subset sufficient. In the ordinary top-k problem, limiting arbitrary inputs changes the answer.
Does allowDiskUse fix a giant result document? No. Disk spill and document-size limits are different constraints. Change the output contract or representation rather than assuming more temporary disk solves every failure.
How do you prove a lookup did not inflate totals? Compare business-event IDs and cardinalities before and after the join, use a fixture with duplicate foreign matches, and check the actual relationship guarantee.
What if the data changes while the report runs? Ask what consistency the report needs and choose deployment-appropriate read semantics. An aggregation pipeline is not a complete consistency specification by itself. Avoid promising a cross-collection snapshot without checking the read concern, transaction context, and supported environment.
Turn one pipeline into a complete practice exercise
Rebuild the five-order report from a blank editor. Predict the output after each stage, then add a missing profile, a duplicate external customer code, a tied total, and an invalid amount. Keep each change small enough that you can calculate the expected answer by hand.
Next, explain the production version without pretending the tiny test is a benchmark. Name the initial index hypothesis, the stage most likely to accumulate memory, and the evidence that would make you revise your design. State which version-specific behavior still needs checking.
Finish with a one-paragraph review: output grain, relationship cardinality, ordering rule, memory growth, and verification. A strong aggregation answer protects the meaning of the data at every stage.
Sources and Further Reading
Research checked September 23, 2026. MongoDB's current manual is version-sensitive; confirm behavior against your deployed server.