Solution: Grouping Across Collections
We'll cover the following...
Query
db.orders.aggregate([// (Optional) limit to 2025{$match: {orderDate: { $gte: ISODate("2025-01-01T00:00:00Z") }}},// One row per product name in the order{$unwind: "$items"},// Join to products by name{$lookup: {from: "products",localField: "items", // product name in ordersforeignField: "name", // product name in productsas: "product"}},{$unwind: "$product"},// Assume quantity = 1 per occurrence; take price from products{$project: {productName: "$product.name",productId: "$product._id",price: "$product.price",quantity: { $literal: 1 },revenue: { $multiply: [ "$product.price", 1 ] }}},// Summaries per product{$group: {_id: "$productId",totalQuantity: { $sum: "$quantity" },totalRevenue: { $sum: "$revenue" }}},{$sort: { totalRevenue: -1 }}])
The explanation of the query is given below:
Line 1: This begins an aggregation pipeline on the
orderscollection.Lines 4–7:
$matchfilters documents before processing further. This keeps only orders placed on or after January 1, 2025. Whereas,$gtemeans “greater than or equal to.”Lines 10–12:
$unwindtakes an array field (items) and creates a separate document for each element. If one order has three items, this stage creates three separate documents, one ...