一对一连接
简介
在本教程中,您可以学习如何使用PyMongo构建聚合管道,对集合进行聚合,并通过完成和运行示例应用程序来打印结果。
此聚合执行一对一连接。当某个集合中的一个文档的字段值与另一个集合中具有相同字段值的单个文档相匹配时,就会发生一对一连接。聚合根据字段值匹配这些文档,并将来自两个来源的信息合并到单个结果中。
提示
一对一连接不需要文档之间存在一对一关系。要了解更多关于此数据关系的信息,请参阅维基百科中关于一对一(数据模型)的条目.
聚合任务摘要
本教程演示了如何将描述产品信息的集合中的数据与描述客户订单的另一个集合中的数据相结合。结果显示了2020年所有订单的列表,包括每个订单相关联的产品详细信息。
此示例使用两个集合
orders
:包含描述商店中产品个别订单的文档products
:包含描述商店销售产品的文档
订单只能包含一个产品,因此聚合使用一对一连接将订单文档与产品文档匹配。这两个集合通过存在于两个集合文档中的名为 product_id
的字段进行连接。
开始之前
在开始本教程之前,请完成聚合模板应用的说明,以设置一个可工作的Python应用程序。
设置应用程序后,通过在应用程序中添加以下代码访问 orders
和 products
集合
orders_coll = agg_db["orders"] products_coll = agg_db["products"]
删除任何现有数据,并按照以下代码将样本数据插入到 orders
集合中
orders_coll.delete_many({}) order_data = [ { "customer_id": "elise_smith@myemail.com", "orderdate": datetime(2020, 5, 30, 8, 35, 52), "product_id": "a1b2c3d4", "value": 431.43 }, { "customer_id": "tj@wheresmyemail.com", "orderdate": datetime(2019, 5, 28, 19, 13, 32), "product_id": "z9y8x7w6", "value": 5.01 }, { "customer_id": "oranieri@warmmail.com", "orderdate": datetime(2020, 1, 1, 8, 25, 37), "product_id": "ff11gg22hh33", "value": 63.13 }, { "customer_id": "jjones@tepidmail.com", "orderdate": datetime(2020, 12, 26, 8, 55, 46), "product_id": "a1b2c3d4", "value": 429.65 } ] orders_coll.insert_many(order_data)
删除任何现有数据,并按照以下代码将样本数据插入到 products
集合中
products_coll.delete_many({}) product_data = [ { "id": "a1b2c3d4", "name": "Asus Laptop", "category": "ELECTRONICS", "description": "Good value laptop for students" }, { "id": "z9y8x7w6", "name": "The Day Of The Triffids", "category": "BOOKS", "description": "Classic post-apocalyptic novel" }, { "id": "ff11gg22hh33", "name": "Morphy Richardds Food Mixer", "category": "KITCHENWARE", "description": "Luxury mixer turning good cakes into great" }, { "id": "pqr678st", "name": "Karcher Hose Set", "category": "GARDEN", "description": "Hose + nosels + winder for tidy storage" } ] products_coll.insert_many(product_data)
教程
为2020年的订单添加一个匹配阶段
添加一个匹配2020年下订单的 $match 阶段
pipeline.append({ "$match": { "orderdate": { "$gte": datetime(2020, 1, 1, 0, 0, 0), "$lt": datetime(2021, 1, 1, 0, 0, 0) } } })
添加一个查找阶段来链接集合
接下来,添加一个 $lookup 阶段。$lookup 阶段将 orders 集合中的 product_id 字段与 products 集合中的 id 字段进行连接
pipeline.append({ "$lookup": { "from": "products", "localField": "product_id", "foreignField": "id", "as": "product_mapping" } })
添加设置阶段来创建新的文档字段
接下来,向管道中添加两个 $set 阶段。
第一个 $set
阶段将 product_mapping
字段设置为在之前的 $lookup
阶段中创建的 product_mapping
对象的第一个元素。
第二个 $set
阶段从 product_mapping
对象字段中的值创建两个新字段,product_name
和 product_category
。
pipeline.extend([ { "$set": { "product_mapping": {"$first": "$product_mapping"} } }, { "$set": { "product_name": "$product_mapping.name", "product_category": "$product_mapping.category" } } ])
提示
由于这是一个一对一的连接,$lookup 阶段仅向输入文档添加一个数组元素。管道使用 $first 操作符从该元素检索数据。
添加一个未设置的阶段以删除不需要的字段
最后,添加一个 $unset 阶段。$unset 阶段从文档中删除不必要的字段
pipeline.append({"$unset": ["_id", "product_id", "product_mapping"]})
解释结果
聚合结果包含三个文档。这些文档代表2020年发生的客户订单,包含订单产品的 product_name
和 product_category
{ 'customer_id': 'elise_smith@myemail.com', 'orderdate': datetime.datetime(2020, 5, 30, 8, 35, 52), 'value': 431.43, 'product_name': 'Asus Laptop', 'product_category': 'ELECTRONICS' } { 'customer_id': 'oranieri@warmmail.com', 'orderdate': datetime.datetime(2020, 1, 1, 8, 25, 37), 'value': 63.13, 'product_name': 'Morphy Richardds Food Mixer', 'product_category': 'KITCHENWARE' } { 'customer_id': 'jjones@tepidmail.com', 'orderdate': datetime.datetime(2020, 12, 26, 8, 55, 46), 'value': 429.65, 'product_name': 'Asus Laptop', 'product_category': 'ELECTRONICS' }
结果包含来自orders
集合和products
集合的文档,通过匹配每个原始文档中存在的product_id
字段进行连接。
要查看此教程的完整代码,请参阅GitHub上的完成的一对一连接应用程序。