Pipeline execution order matters in MongoDB - Time & Space Complexity
When using MongoDB pipelines, the order of steps affects how long the query takes.
We want to know how the number of operations changes as the data flows through each step.
Analyze the time complexity of the following MongoDB aggregation pipeline.
db.collection.aggregate([
{ $match: { status: "active" } },
{ $group: { _id: "$category", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } }
])
This pipeline filters active records, groups them by category summing amounts, then sorts by total.
Look at the steps that repeat over the data:
- Primary operation: Scanning all documents to filter with $match.
- How many times: Once for each document in the collection.
- Grouping then processes each matched document once.
- Sorting processes each group once after grouping.
As the number of documents grows, the operations increase roughly like this:
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 scans, grouping, and sorting a few groups |
| 100 | About 100 scans, grouping, and sorting more groups |
| 1000 | About 1000 scans, grouping, and sorting many groups |
Pattern observation: The first step scans all documents, so operations grow directly with input size.
Time Complexity: O(n log n)
This means the time grows a bit faster than the number of documents because sorting adds extra steps.
[X] Wrong: "The order of pipeline steps does not affect performance."
[OK] Correct: Filtering early reduces data size for later steps, making the whole pipeline faster.
Understanding how pipeline order affects time helps you write faster queries and shows you think about efficiency.
"What if we moved the $sort step before the $match? How would the time complexity change?"
Practice
Solution
Step 1: Understand pipeline execution
MongoDB executes pipeline stages sequentially in the order they appear.Step 2: Impact of order on results and performance
Changing the order can change the output and how fast the query runs, especially filtering early helps performance.Final Answer:
Because stages run in the order they are written, affecting results and performance -> Option AQuick Check:
Pipeline order affects output and speed [OK]
- Thinking MongoDB runs stages in parallel
- Believing order does not affect output
- Assuming MongoDB reorders stages automatically
Solution
Step 1: Identify correct aggregation syntax
The aggregate method takes an array of stages, each stage is an object with a stage operator like $match.Step 2: Check each option
db.collection.aggregate([{ $match: { status: 'A' } }]) correctly uses an array with $match stage. db.collection.aggregate({ $match: { status: 'A' } }) misses array brackets. db.collection.find({ $match: { status: 'A' } }) uses find() which is not aggregation. db.collection.aggregate([{ match: { status: 'A' } }]) misses $ in $match.Final Answer:
db.collection.aggregate([{ $match: { status: 'A' } }]) -> Option AQuick Check:
Aggregation stages are in an array [OK]
- Omitting the array brackets around stages
- Using find() instead of aggregate() for pipelines
- Missing $ in stage operators like $match
db.orders.aggregate([
{ $sort: { price: -1 } },
{ $match: { status: 'A' } }
])What is the main issue with this pipeline?
Solution
Step 1: Analyze stage order
The pipeline sorts all documents first, then filters with $match.Step 2: Understand performance impact
Filtering first reduces documents early, making sorting faster. Sorting before filtering wastes resources.Final Answer:
It filters after sorting, which is less efficient -> Option DQuick Check:
Filter early, then sort for best performance [OK]
- Thinking stage order causes syntax errors
- Believing $match must always be first to work
- Confusing sort order direction
db.sales.aggregate([
{ $group: { _id: "$item", total: { $sum: "$amount" } } },
{ $match: { $gt: ["$total", 100] } }
])What is the likely cause?
Solution
Step 1: Identify the invalid $match syntax
The $match stage uses aggregation expression syntax { $gt: ["$total", 100] } directly, which is not valid query selector syntax.Step 2: Use $expr for aggregation expressions
To use expression operators like $gt with field paths and literals in array form, wrap in $expr: { $match: { $expr: { $gt: ["$total", 100] } } }.Final Answer:
The $match stage should use $expr to filter on computed fields -> Option BQuick Check:
$expr enables agg expressions in $match [OK]
- Trying to filter grouped fields without $expr
- Placing $match before $group expecting same results
- Assuming $group syntax is wrong
Solution
Step 1: Filter early for performance
Applying $match first reduces documents to only those with status 'A'.Step 2: Sort and limit after filtering
Sorting after filtering is faster, then $limit picks top 3.Step 3: Check other options
db.products.aggregate([ { $sort: { price: -1 } }, { $limit: 3 }, { $match: { status: 'A' } } ]) sorts all documents before filtering, wasting resources. db.products.aggregate([ { $limit: 3 }, { $match: { status: 'A' } }, { $sort: { price: -1 } } ]) limits before filtering, wrong results. db.products.aggregate([ { $match: { status: 'A' } }, { $limit: 3 }, { $sort: { price: -1 } } ]) limits before sorting, wrong order.Final Answer:
db.products.aggregate([ { $match: { status: 'A' } }, { $sort: { price: -1 } }, { $limit: 3 } ]) -> Option CQuick Check:
Filter, then sort, then limit [OK]
- Sorting before filtering wastes resources
- Limiting before sorting gives wrong top results
- Filtering after limiting misses correct documents
Ready to prove it?
Pass the test and this pattern moves unknown
