$lookup with pipeline (advanced join) in MongoDB - Time & Space Complexity
When using $lookup with a pipeline in MongoDB, we want to understand how the time it takes grows as the data gets bigger.
We ask: How does the number of operations change when joining collections with a pipeline?
Analyze the time complexity of the following code snippet.
db.orders.aggregate([
{
$lookup: {
from: "products",
let: { order_item: "$item" },
pipeline: [
{ $match: { $expr: { $eq: ["$name", "$$order_item"] } } },
{ $project: { price: 1, _id: 0 } }
],
as: "productDetails"
}
}
])
This code joins the orders collection with products using a pipeline to match and project product details for each order item.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: For each document in
orders, the pipeline runs a$matchonproducts. - How many times: Once per
ordersdocument, so the number ofordersdocuments times the cost of matching inproducts.
As the number of orders grows, the pipeline runs more times. Each run searches products for matches.
| Input Size (orders) | Approx. Operations |
|---|---|
| 10 | 10 x cost of matching in products |
| 100 | 100 x cost of matching in products |
| 1000 | 1000 x cost of matching in products |
Pattern observation: The total work grows roughly in direct proportion to the number of orders documents.
Time Complexity: O(n x m)
This means the time grows with the number of orders (n) times the number of products (m) scanned per lookup.
[X] Wrong: "The $lookup with pipeline runs just once regardless of input size."
[OK] Correct: Actually, the pipeline runs once for each orders document, so the work multiplies with input size.
Understanding how $lookup with pipelines scales helps you explain data joining costs clearly, a useful skill when discussing database performance.
What if we added an index on the products.name field used in $match? How would the time complexity change?
Practice
$lookup with a pipeline in MongoDB?Solution
Step 1: Understand $lookup basic function
$lookup is used to join documents from another collection into the current one.Step 2: Role of pipeline in $lookup
Using a pipeline allows filtering and transforming the joined documents before adding them.Final Answer:
To perform advanced joins with filtering and transformations on the joined data -> Option CQuick Check:
$lookup with pipeline = advanced join [OK]
- Thinking $lookup with pipeline updates or deletes data
- Confusing $lookup with index creation
- Assuming $lookup merges collections permanently
pipeline of a $lookup stage?Solution
Step 1: Recall $lookup variable syntax
Variables for the pipeline are defined using theletkeyword as an object.Step 2: Match correct keyword and structure
Onlyletwith an object of key-value pairs is valid syntax.Final Answer:
"let: { var1: \"$field1\", var2: \"$field2\" }" -> Option DQuick Check:
Variables in $lookup pipeline = let [OK]
- Using 'vars' or 'variables' instead of 'let'
- Using array syntax instead of object for variables
- Omitting the $ sign before field names
orders and products, what will be the output of this aggregation on orders?
{
$lookup: {
from: "products",
let: { prod_id: "$productId" },
pipeline: [
{ $match: { $expr: { $eq: ["$_id", "$$prod_id"] } } },
{ $project: { name: 1, price: 1, _id: 0 } }
],
as: "productDetails"
}
}Solution
Step 1: Understand $lookup with pipeline and let
Theletdefinesprod_idfromorders.productId. The pipeline matchesproducts._idto this variable.Step 2: Analyze pipeline stages
The pipeline filters products matching the order's productId and projects only name and price fields, excluding _id.Final Answer:
Each order document will have a new field 'productDetails' containing an array with matching product's name and price -> Option BQuick Check:
$lookup with pipeline returns array of matched docs [OK]
- Expecting a single object instead of an array
- Using wrong variable reference syntax like '$prod_id' instead of '$$prod_id'
- Forgetting to project fields inside pipeline
{
$lookup: {
from: "employees",
let: { empId: "$employeeId" },
pipeline: [
{ $match: { $expr: { $eq: ["$_id", "$$empId"] } } }
],
as: "employeeInfo"
}
}Solution
Step 1: Check variable usage in $expr
Variables defined inletmust be referenced with double dollar signs$$inside the pipeline.Step 2: Identify incorrect variable reference
The code uses"$empId"instead of"$$empId", causing a runtime error.Final Answer:
Variable reference inside $expr should be "$$empId" instead of "$empId" -> Option AQuick Check:
Use $$ to reference let variables inside pipeline [OK]
- Using single $ instead of double $$ for let variables
- Misplacing let outside $lookup
- Incorrect data type for 'from' field
orders with products but only include products priced above 100 in the joined array. Which $lookup pipeline correctly achieves this?Solution
Step 1: Understand filtering with $expr and $and
We must match documents where _id equals the variable and price is greater than 100 in a single $match using $expr and $and.Step 2: Analyze each option's pipeline
{ $lookup: { from: "products", let: { pid: "$productId" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: ["$_id", "$$pid"] }, { $gt: ["$price", 100] } ] } } } ], as: "expensiveProduct" } } correctly uses $expr with $and combining both conditions. { $lookup: { from: "products", localField: "productId", foreignField: "_id", as: "expensiveProduct", pipeline: [ { $match: { price: { $gt: 100 } } } ] } } wrongly uses pipeline with localField/foreignField which is invalid. { $lookup: { from: "products", let: { pid: "$productId" }, pipeline: [ { $match: { _id: "$$pid", price: { $gt: 100 } } } ], as: "expensiveProduct" } } uses invalid $match syntax inside pipeline. { $lookup: { from: "products", let: { pid: "$productId" }, pipeline: [ { $match: { $expr: { $eq: ["$_id", "$$pid"] } } }, { $match: { price: { $gt: 100 } } } ], as: "expensiveProduct" } } splits conditions into two $match stages, but second $match cannot use field without $expr inside pipeline.Final Answer:
Option A correctly filters joined products priced above 100 using $expr and $and -> Option AQuick Check:
Use $expr with $and for multiple conditions in $lookup pipeline [OK]
- Using localField/foreignField with pipeline together
- Splitting conditions into multiple $match without $expr
- Incorrect $match syntax inside pipeline
Ready to prove it?
Pass the test and this pattern moves unknown
