For AI agents: a documentation index is available at https://www.mongodb.com/docs/llms.txt — markdown versions of all pages are available by appending .md to any URL path.

Perform Multi-Field Joins

This tutorial illustrates how to construct an aggregation pipeline, perform the aggregation on a collection, and display the results using the language of your choice.

This tutorial demonstrates how to combine data from a collection that describes product information with another collection that describes customer orders. The results show a list of products ordered in 2020 and details about each order.

This aggregation performs a multi-field join by using $lookup. A multi-field join occurs when there are multiple corresponding fields in the documents of two collections. The aggregation matches these documents on the corresponding fields and combines information from both into one document.


➤ Use the Select your language drop-down menu in the upper-right to set the language of the following examples or select MongoDB Shell.


This example uses two collections:

  • products, which contains documents describing the products that a shop sells

  • orders, which contains documents describing individual orders for products in a shop

An order can only contain one product. The aggregation uses a multi-field join to match a product document to documents representing orders of that product. The aggregation joins collections by the name and variation fields in documents in the products collection, corresponding to the product_name and product_variation fields in documents in the orders collection.

To create the orders and products collections, use the insertMany() method:

db.orders.deleteMany({}) db.orders.insertMany( [ { customer_id: "elise_smith@myemail.com", orderdate: new Date("2020-05-30T08:35:52Z"), product_name: "Asus Laptop", product_variation: "Standard Display", value: 431.43, }, { customer_id: "tj@wheresmyemail.com", orderdate: new Date("2019-05-28T19:13:32Z"), product_name: "The Day Of The Triffids", product_variation: "2nd Edition", value: 5.01, }, { customer_id: "oranieri@warmmail.com", orderdate: new Date("2020-01-01T08:25:37Z"), product_name: "Morphy Richards Food Mixer", product_variation: "Deluxe", value: 63.13, }, { customer_id: "jjones@tepidmail.com", orderdate: new Date("2020-12-26T08:55:46Z"), product_name: "Asus Laptop", product_variation: "Standard Display", value: 429.65, }] )
db.products.deleteMany({}) db.products.insertMany( [ { name: "Asus Laptop", variation: "Ultra HD", category: "ELECTRONICS", description: "Great for watching movies" }, { name: "Asus Laptop", variation: "Standard Display", category: "ELECTRONICS", description: "Good value laptop for students" }, { name: "The Day Of The Triffids", variation: "1st Edition", category: "BOOKS", description: "Classic post-apocalyptic novel" }, { name: "The Day Of The Triffids", variation: "2nd Edition", category: "BOOKS", description: "Classic post-apocalyptic novel" }, { name: "Morphy Richards Food Mixer", variation: "Deluxe", category: "KITCHENWARE", description: "Luxury mixer turning good cakes into great" }] )

The following steps demonstrate how to create and run an aggregation pipeline to join collections on multiple fields.

1

The first stage of the pipeline is a $lookup stage to join the orders collection to the products collection by two fields in each collection. The $lookup stage contains an embedded pipeline to configure the join.

embedded_pl = [ // Stage 1: Match the values of two fields on each side of the join // The $eq filter uses aliases for the name and variation fields set { $match: { $expr: { $and: [ { $eq: ["$product_name", "$$prdname"] }, { $eq: ["$product_variation", "$$prdvartn"] } ] } } }, // Stage 2: Match orders placed in 2020 { $match: { orderdate: { $gte: new Date("2020-01-01T00:00:00Z"), $lt: new Date("2021-01-01T00:00:00Z") } } }, // Stage 3: Remove unneeded fields from the orders collection side of the join { $unset: ["_id", "product_name", "product_variation"] }]
2
db.products.aggregate( [ // Use the embedded pipeline in a lookup stage { $lookup: { from: "orders", let: { prdname: "$name", prdvartn: "$variation" }, pipeline: embedded_pl, as: "orders" } }, // Match products ordered in 2020 { $match: { orders: { $ne: [] } } }, // Remove unneeded fields { $unset: ["_id", "description"] }] )
3

The aggregated results contain two documents. The documents represent products ordered 2020. Each document contains an orders array field that lists details about each order for that product.

{ name: 'Asus Laptop', variation: 'Standard Display', category: 'ELECTRONICS', orders: [ { customer_id: 'elise_smith@myemail.com', orderdate: ISODate('2020-05-30T08:35:52.000Z'), value: 431.43 }, { customer_id: 'jjones@tepidmail.com', orderdate: ISODate('2020-12-26T08:55:46.000Z'), value: 429.65 } ]}{ name: 'Morphy Richards Food Mixer', variation: 'Deluxe', category: 'KITCHENWARE', orders: [ { customer_id: 'oranieri@warmmail.com', orderdate: ISODate('2020-01-01T08:25:37.000Z'), value: 63.13 } ]}
Select your language
Rate this page