$lookup with pipeline lets you join data from two collections in MongoDB with more control. It helps when you want to filter, transform, or match data during the join.
$lookup with pipeline (advanced join) in MongoDB
db.collection.aggregate([
{
$lookup: {
from: "otherCollection",
let: { var1: "$field1", var2: "$field2" },
pipeline: [
{ $match: { $expr: { /* expression using $$var1, $$var2 */ } } },
{ /* other pipeline stages */ }
],
as: "joinedField"
}
}
])Use let to define variables from the current collection's fields.
Inside pipeline, use $expr and $$ to access these variables for matching.
db.orders.aggregate([
{
$lookup: {
from: "products",
let: { order_item: "$item" },
pipeline: [
{ $match: { $expr: { $eq: ["$product_name", "$$order_item"] } } },
{ $project: { product_name: 1, price: 1, _id: 0 } }
],
as: "order_details"
}
}
])db.students.aggregate([
{
$lookup: {
from: "grades",
let: { student_id: "$id" },
pipeline: [
{ $match: { $expr: { $eq: ["$studentId", "$$student_id"] } } },
{ $match: { score: { $gte: 70 } } }
],
as: "passing_grades"
}
}
])This query joins each employee with their department info by matching departmentId in employees to _id in departments. It only includes the department's name and location.
db.employees.aggregate([
{
$lookup: {
from: "departments",
let: { dept_id: "$departmentId" },
pipeline: [
{ $match: { $expr: { $eq: ["$_id", "$$dept_id"] } } },
{ $project: { name: 1, location: 1, _id: 0 } }
],
as: "department_info"
}
}
])Remember that $lookup with pipeline can be slower than simple joins because it runs a mini-aggregation for each document.
Use $expr inside $match to compare fields and variables.
The result of $lookup is always an array, even if it contains one or zero documents.
$lookup with pipeline lets you do advanced joins with filtering and transformations.
You define variables from the main collection using let and use them inside the pipeline.
The joined data is returned as an array in the specified as field.
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
