How does the $lookup stage perform joins in MongoDB aggregation?
Understand how MongoDB's $lookup stage performs left outer joins in aggregation, its equality and pipeline forms, $unwind, and indexing for performance.
Expected Interview Answer
The $lookup stage performs a left outer join in the MongoDB aggregation pipeline: for each input document it finds matching documents in a target collection and adds them as an array field, keeping every input document even when no match is found.
The equality form matches a localField on the input against a foreignField in the joined collection. The pipeline form runs a sub-pipeline over the foreign collection using let-bound variables, enabling multiple conditions, joins on non-equality, and pre-filtering. Because results are embedded as an array, you often follow $lookup with $unwind to flatten them. Performance depends heavily on an index existing on the foreignField.
- Joins data across collections within one pipeline
- Left-outer semantics keep unmatched input documents
- Pipeline form supports complex, multi-condition joins
- Avoids extra application-side round trips
- Combines naturally with $unwind and $match
AI Mentor Explanation
A $lookup is like a scorer holding each batter's name and flipping to the squad register to attach that player's full profile beside every scorecard row. Every batting entry is kept even if the register has no photo yet — an unmatched name still stays on the sheet. The register lookup by name mirrors matching localField to foreignField and appending the found details as an array.
Step-by-Step Explanation
Step 1
Choose the join form
Use the equality syntax (localField/foreignField) for simple ID joins or the pipeline syntax for complex conditions.
Step 2
Specify from and as
Set 'from' to the target collection and 'as' to the array field where matched documents will be embedded.
Step 3
Match documents
MongoDB finds foreign documents where foreignField equals localField (or where the sub-pipeline matches).
Step 4
Embed results
Matches are added as an array under the 'as' field; unmatched inputs get an empty array (left outer join).
Step 5
Flatten if needed
Follow with $unwind to turn the array into individual documents, then $match or $project as required.
What Interviewer Expects
- Knowing $lookup is a left outer join
- Understanding localField/foreignField matching
- Awareness of the pipeline form with let variables
- Results are embedded as an array, often unwound
- Importance of indexing the foreignField for performance
Common Mistakes
- Thinking $lookup drops unmatched documents like an inner join
- Forgetting to $unwind the resulting array before further stages
- Not indexing the foreignField, causing slow collection scans
- Confusing the equality form with the pipeline form's let/pipeline keys
- Assuming $lookup can join across separate databases
Best Answer (HR Friendly)
“The $lookup stage lets MongoDB combine data from two collections in a single query, similar to a join in SQL. For each record it looks up related records in another collection and attaches them as a list, keeping every original record even when nothing matches. It saves the app from making extra separate queries.”
Code Example
db.orders.aggregate([
{
$lookup: {
from: 'customers',
localField: 'customerId',
foreignField: '_id',
as: 'customer'
}
},
{ $unwind: { path: '$customer', preserveNullAndEmptyArrays: true } },
{ $project: { total: 1, 'customer.name': 1 } }
])db.orders.aggregate([
{
$lookup: {
from: 'products',
let: { pid: '$productId', qty: '$quantity' },
pipeline: [
{ $match: { $expr: { $and: [
{ $eq: ['$_id', '$$pid'] },
{ $lte: ['$minOrder', '$$qty'] }
] } } },
{ $project: { name: 1, price: 1 } }
],
as: 'product'
}
}
])Follow-up Questions
- How does the pipeline form of $lookup differ from the equality form?
- Why is $lookup often followed by $unwind?
- How do indexes affect $lookup performance?
- Can $lookup join collections in different databases or shards?
- When would you prefer embedding over using $lookup at query time?
MCQ Practice
1. What type of join does the $lookup stage perform?
$lookup performs a left outer join: every input document is kept, with matches added as an array (empty if none).
2. In the equality form of $lookup, the input document's field is specified by:
localField is the input collection's field; it is matched against foreignField in the 'from' collection.
3. Which stage is commonly used right after $lookup to flatten its results?
$lookup embeds matches as an array, so $unwind is used to turn that array into individual documents.
Flash Cards
What join does $lookup perform? — A left outer join across collections, embedding matches as an array field.
Equality-form keys of $lookup? — from, localField, foreignField, and as.
Why follow $lookup with $unwind? — To flatten the embedded array into individual documents for further stages.
Biggest performance lever for $lookup? — An index on the foreignField in the joined collection.
Continue Learning
Related Interview Questions
What are the trade-offs between normalization and denormalization in MongoDB?
medium
What is the MongoDB aggregation pipeline and how does it work?
medium
What is the difference between embedding and referencing in MongoDB data modeling?
medium
What is the difference between find() and aggregate() in MongoDB?
medium