Docs 菜单

Docs 主页开发应用程序Python 驱动程序pymongo

多字段连接

在此页面上

  • 简介
  • 聚合任务摘要
  • 开始之前
  • Tutorial
  • 添加查找阶段以链接collection和导入字段
  • 为 2020 年订购的产品添加匹配阶段
  • 添加未设置阶段以删除不需要的字段
  • 运行聚合管道
  • 解释结果

在本教程中,您可以学习如何使用 PyMongo 构建聚合管道,对集合执行聚合,并通过完成和运行示例应用来打印结果。

此聚合执行多字段联接。 当您用来将文档匹配在一起的两个collection的文档中有多个相应字段时,就会发生多字段连接。聚合将这些文档的字段值进行匹配,并将两者的信息合并到一个文档中。

提示

一对多连接

一对多联接是多字段联接的一种变体。 执行一对多联接时,您可以从一个文档中选择一个字段,该字段与联接另一端的多个文档中的字段值匹配。 要了解有关这些数据关系的详情,请参阅维基百科有关 一对多(数据模型) 的条目 多对多(数据模型)。

本教程演示如何将描述产品信息的集合与描述客户订单的另一个集合中的数据组合起来。 结果显示 2020 年订购的产品列表,其中还包含每个订单的详细信息。

此示例使用两个集合:

  • products,其中包含描述商店销售的产品的文档

  • orders,其中包含描述商店中产品的单个订单的文档

一份订单只能包含一种产品,因此聚合使用多字段联接将产品文档与表示该产品订单的文档进行匹配。 这些collection由productscollection中的文档中的namevariation字段连接,对应于orderscollection中的文档中的product_nameproduct_variation字段。

在开始本教程之前,请完成聚合模板应用说明以设立有效的Python应用程序。

设置应用后,通过将以下代码添加到应用程序来访问productsorderscollection:

products_coll = agg_db["products"]
orders_coll = agg_db["orders"]

删除所有现有数据,并将样本数据插入products collection,如以下代码所示:

products_coll.delete_many({})
products_data = [
{
"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"
}
]
products_coll.insert_many(products_data)

删除所有现有数据,并将样本数据插入orders collection,如以下代码所示:

orders_coll.delete_many({})
order_data = [
{
"customer_id": "elise_smith@myemail.com",
"orderdate": datetime(2020, 5, 30, 8, 35, 52),
"product_name": "Asus Laptop",
"product_variation": "Standard Display",
"value": 431.43
},
{
"customer_id": "tj@wheresmyemail.com",
"orderdate": datetime(2019, 5, 28, 19, 13, 32),
"product_name": "The Day Of The Triffids",
"product_variation": "2nd Edition",
"value": 5.01
},
{
"customer_id": "oranieri@warmmail.com",
"orderdate": datetime(2020, 1, 1, 8, 25, 37),
"product_name": "Morphy Richards Food Mixer",
"product_variation": "Deluxe",
"value": 63.13
},
{
"customer_id": "jjones@tepidmail.com",
"orderdate": datetime(2020, 12, 26, 8, 55, 46),
"product_name": "Asus Laptop",
"product_variation": "Standard Display",
"value": 429.65
}
]
orders_coll.insert_many(order_data)
1

管道的第一阶段是 $lookup 阶段,通过每个集合中的两个字段将 orders 集合连接到 products 集合。查找阶段包含一个用于配置连接的嵌入式管道。

在嵌入式管道中,添加$match阶段以匹配联接两侧的两个字段的值。 请注意,以下代码使用创建$lookup阶段时设置的namevariation字段的别名:

embedded_pl = [
{
"$match": {
"$expr": {
"$and": [
{"$eq": ["$product_name", "$$prdname"]},
{"$eq": ["$product_variation", "$$prdvartn"]}
]
}
}
}
]

在嵌入式管道中,添加另一个 $match 阶段,以匹配在 2020 下达的订单:

embedded_pl.append({
"$match": {
"orderdate": {
"$gte": datetime(2020, 1, 1, 0, 0, 0),
"$lt": datetime(2021, 1, 1, 0, 0, 0)
}
}
})

在嵌入式管道中,添加 $unset 阶段,以便从连接的 orders 集合一侧删除不需要的字段:

embedded_pl.append({
"$unset": ["_id", "product_name", "product_variation"]
})

嵌入式管道完成后,将$lookup阶段添加到主聚合管道。 配置此阶段以将处理后的查找字段存储在名为orders的数组字段中:

pipeline.append({
"$lookup": {
"from": "orders",
"let": {
"prdname": "$name",
"prdvartn": "$variation"
},
"pipeline": embedded_pl,
"as": "orders"
}
})
2

接下来,根据上一步计算得出的 orders 数组,添加 $match 阶段,以仅显示在 2020 中至少有一个订单的产品:

pipeline.append({
"$match": {
"orders": {"$ne": []}
}
})
3

最后,添加 $unset 阶段。$unset 阶段从结果文档中移除 _iddescription 字段:

pipeline.append({
"$unset": ["_id", "description"]
})
4

将以下代码添加到应用程序末尾,以对productscollection执行聚合:

aggregation_result = products_coll.aggregate(pipeline)

最后,在 shell 中运行以下命令以启动应用程序:

python3 agg_tutorial.py
5

聚合结果包含两个文档。 这些文档代表 2020 年有订单的产品。 每个文档都包含一个orders数组字段,其中列出了该产品的每个订单的详细信息:

{
'name': 'Asus Laptop',
'variation': 'Standard Display',
'category': 'ELECTRONICS',
'orders': [
{
'customer_id': 'elise_smith@myemail.com',
'orderdate': datetime.datetime(2020, 5, 30, 8, 35, 52),
'value': 431.43
},
{
'customer_id': 'jjones@tepidmail.com',
'orderdate': datetime.datetime(2020, 12, 26, 8, 55, 46),
'value': 429.65
}
]
}
{
'name': 'Morphy Richards Food Mixer',
'variation': 'Deluxe',
'category': 'KITCHENWARE',
'orders': [
{
'customer_id': 'oranieri@warmmail.com',
'orderdate': datetime.datetime(2020, 1, 1, 8, 25, 37),
'value': 63.13
}
]
}

结果文档包含orders集合和products集合中文档的详细信息,并由产品名称和变体连接起来。

要查看本教程的完整代码,请参阅 Github 上已完成的多字段加入应用

← 一对一连接