多字段连接
简介
在本教程中,您可以学习如何使用Node.js驱动程序构建聚合管道,在集合上执行聚合,并通过完成并运行一个示例应用程序来打印结果。
此聚合执行多字段连接。多字段连接发生在您使用的两个集合的文档中有多个对应的字段时,用于匹配文档。聚合将这些文档匹配在字段值上,并将两方面的信息合并到一个文档中。
提示
一对一连接
一对一连接是多字段连接的一种形式。当您执行一对一连接时,从匹配字段值的多份文档中选择一个字段。要了解更多关于这些数据关系的信息,请参阅维基百科条目一对一(数据模型) 和 多对多(数据模型)。
聚合任务摘要
本教程演示了如何将描述产品信息的集合数据与另一个描述客户订单的集合数据结合起来。结果展示了一个包含2020年订单详情的产品列表。
此示例使用了两个集合
products
,其中包含描述商店销售的产品的文档orders
,其中包含描述商店中产品单个订单的文档
一个订单只能包含一个产品,因此聚合使用多字段连接来匹配产品文档和表示该产品订单的文档。通过在products
集合中的文档中的name
和variation
字段与在orders
集合中的文档中的product_name
和product_variation
字段相匹配,将集合连接起来。
在开始之前
在开始本教程之前,请完成聚合模板应用程序说明,以设置一个可工作的Node.js应用程序。
设置应用程序后,通过将以下代码添加到应用程序中,访问products
和orders
集合
const productsColl = aggDB.collection("products"); const ordersColl = aggDB.collection("orders");
删除任何现有数据,并按以下代码将示例数据插入到products
集合中
await productsColl.deleteMany({}); const productsData = [ { 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", }, ]; await productsColl.insertMany(productsData);
删除任何现有数据,并按以下代码将示例数据插入到orders
集合中
await ordersColl.deleteMany({}); const orderData = [ { 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, }, ]; await ordersColl.insertMany(orderData);
教程
添加一个查找阶段来连接集合并导入字段
管道的第一阶段是一个$lookup阶段,用于通过每个集合中的两个字段将orders
集合与products
集合进行连接。查找阶段包含一个嵌入式管道来配置连接。
在嵌入式管道中,添加一个$match阶段,以匹配连接两边的两个字段的值。注意以下代码使用别名来引用在创建$lookup阶段时设置的name
和variation
字段。
const embedded_pl = []; embedded_pl.push({ $match: { $expr: { $and: [ { $eq: ["$product_name", "$$prdname"] }, { $eq: ["$product_variation", "$$prdvartn"] }, ], }, }, });
在嵌入式管道中,再添加一个$match阶段,以匹配2020年下的订单。
embedded_pl.push({ $match: { orderdate: { $gte: new Date("2020-01-01T00:00:00Z"), $lt: new Date("2021-01-01T00:00:00Z"), }, }, });
在嵌入式管道中,添加一个$unset阶段,从连接的orders
集合端删除不需要的字段。
embedded_pl.push({ $unset: ["_id", "product_name", "product_variation"], });
嵌入式管道完成后,将$lookup
阶段添加到主聚合管道中。配置此阶段,将处理后的查找字段存储在一个名为orders
的数组字段中。
pipeline.push({ $lookup: { from: "orders", let: { prdname: "$name", prdvartn: "$variation", }, pipeline: embedded_pl, as: "orders", }, });
添加一个匹配阶段,匹配2020年下的订单
接下来,添加一个$match阶段,仅显示在2020年至少有一个订单的产品,基于上一步计算的orders
数组。
pipeline.push({ $match: { orders: { $ne: [] }, }, });
添加一个unset阶段来删除不需要的字段
最后,添加一个$unset阶段。$unset阶段从结果文档中删除_id
和description
字段。
pipeline.push({ $unset: ["_id", "description"], });
解读结果
聚合结果包含两个文档。这些文档表示在2020年有订单的产品。每个文档都包含一个orders
数组字段,列出了该产品的每个订单的详细信息
{ name: 'Asus Laptop', variation: 'Standard Display', category: 'ELECTRONICS', orders: [ { customer_id: 'elise_smith@myemail.com', orderdate: 2020-05-30T08:35:52.000Z, value: 431.43 }, { customer_id: 'jjones@tepidmail.com', orderdate: 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: 2020-01-01T08:25:37.000Z, value: 63.13 } ] }
结果文档包含来自orders
集合和products
集合的文档的详细信息,并通过产品名称和变体进行连接。
要查看本教程的完整代码,请参阅GitHub上的完成的多个字段连接应用程序。