MongoDB $lookup with conditional foreignField
MongoDB $lookup with conditional foreignField
游乐场:https://mongoplayground.net/p/OxMnsCFZpmQ
我的MongoDB版本:4.2.
我有一个集合 car_parts
和 customers
。
顾名思义,car_parts
有汽车零件,其中一些零件可以有一个字段 sub_parts
,它是该零件包含的 car_parts._id
的列表。
每位在我们这里购买商品的客户都存储在 customers
中。客户的 parts
字段包含客户在特定日期一起购买的零件列表。
我想在 MongoDB 中进行聚合查询,即 returns 从 customers
购买了哪些汽车零件 (bought_parts
) 的映射。但是,如果 car_parts
有字段 sub_parts
,客户应该只出现在子部分。
所以 playground 中的查询已经给出了几乎正确的结果,除了 sub_parts
主题。
customer_3 示例:
{
"_id": "customer_3",
"parts": [
{
"bought_parts": [
3
],
date: "15.07.2020"
}
]
}
因为 bought_parts
有 car_parts._id
= 3:
{
"_id": 3,
"name": "steering wheel",
"sub_parts": [
1, // other car_parts._id s
2
]
}
结果应显示 customer_3 作为汽车部件 1 和 2 的客户。
我不确定如何完成此操作,但我假设用实际 ID [1,2] 来“临时”替换 bought_parts
中的 ID 3 可能会解决问题。
预期输出:
[
{
"_id": 1,
"customers": [
"customer_1",
"customer_2",
"customer_3" // <- since customer_3 bought car part 3 which has 1 in sub_parts
]
},
{
"_id": 2,
"customers": [
"customer_3" // <- since customer_3 bought car part 3 which has 2 in sub_parts
]
},
{
"_id": 3,
"customers": [
"customer_1", // <- since car_parts.id = 3 has [1, 2] in sub_parts, show customers of ids [1, 2]
"customer_2",
"customer_3"
]
},
{
"_id": 4,
"customers": [
"customer_1",
"customer_2"
]
}
]
非常感谢!
编辑:一种方法是:
db.car_parts.aggregate([
{
$project: {
topLevel: {$concatArrays: [{$ifNull: ["$sub_parts", []]}, ["$_id"]]},
sub_parts: 1
}
},
{$unwind: "$topLevel"},
{
$group: {
_id: "$topLevel",
parts: {$push: "$_id"},
sub_parts: {$first: "$sub_parts"}
}
},
{
$project: {
parts: {$concatArrays: [{"$ifNull": ["$sub_parts", []]}, "$parts"]}
}
},
{
$lookup: {
from: "customers",
localField: "parts",
foreignField: "parts.scanned_parts",
as: "customers"
}
},
{$project: {customers: "$customers._id"}}
])
如您所见,正在处理 this playground。
既然你说sub-parts只有一层,我就换个思路:在$lookup
之前创建一个顶层。例如,由于您希望使用第 3 部分的客户在第 1,2 部分(共 3 个 sub-parts)下注册,因此我们的想法是将它们分组。 $lookup
之后的这种连接有点笨拙,但是如果我们使用 $lookup
之前的 car_parts
集合中的数据,我们实际上已经知道第 1、2 部分是子部分of 3. 创建一个 topLevel
临时字段,允许预先对所有部件和 sub-parts 进行分组,如果客户使用它们,他应该在这个顶级部件下注册。这让事情变得更加优雅......
游乐场:https://mongoplayground.net/p/OxMnsCFZpmQ
我的MongoDB版本:4.2.
我有一个集合 car_parts
和 customers
。
顾名思义,car_parts
有汽车零件,其中一些零件可以有一个字段 sub_parts
,它是该零件包含的 car_parts._id
的列表。
每位在我们这里购买商品的客户都存储在 customers
中。客户的 parts
字段包含客户在特定日期一起购买的零件列表。
我想在 MongoDB 中进行聚合查询,即 returns 从 customers
购买了哪些汽车零件 (bought_parts
) 的映射。但是,如果 car_parts
有字段 sub_parts
,客户应该只出现在子部分。
所以 playground 中的查询已经给出了几乎正确的结果,除了 sub_parts
主题。
customer_3 示例:
{
"_id": "customer_3",
"parts": [
{
"bought_parts": [
3
],
date: "15.07.2020"
}
]
}
因为 bought_parts
有 car_parts._id
= 3:
{
"_id": 3,
"name": "steering wheel",
"sub_parts": [
1, // other car_parts._id s
2
]
}
结果应显示 customer_3 作为汽车部件 1 和 2 的客户。
我不确定如何完成此操作,但我假设用实际 ID [1,2] 来“临时”替换 bought_parts
中的 ID 3 可能会解决问题。
预期输出:
[
{
"_id": 1,
"customers": [
"customer_1",
"customer_2",
"customer_3" // <- since customer_3 bought car part 3 which has 1 in sub_parts
]
},
{
"_id": 2,
"customers": [
"customer_3" // <- since customer_3 bought car part 3 which has 2 in sub_parts
]
},
{
"_id": 3,
"customers": [
"customer_1", // <- since car_parts.id = 3 has [1, 2] in sub_parts, show customers of ids [1, 2]
"customer_2",
"customer_3"
]
},
{
"_id": 4,
"customers": [
"customer_1",
"customer_2"
]
}
]
非常感谢!
编辑:一种方法是:
db.car_parts.aggregate([
{
$project: {
topLevel: {$concatArrays: [{$ifNull: ["$sub_parts", []]}, ["$_id"]]},
sub_parts: 1
}
},
{$unwind: "$topLevel"},
{
$group: {
_id: "$topLevel",
parts: {$push: "$_id"},
sub_parts: {$first: "$sub_parts"}
}
},
{
$project: {
parts: {$concatArrays: [{"$ifNull": ["$sub_parts", []]}, "$parts"]}
}
},
{
$lookup: {
from: "customers",
localField: "parts",
foreignField: "parts.scanned_parts",
as: "customers"
}
},
{$project: {customers: "$customers._id"}}
])
如您所见,正在处理 this playground。
既然你说sub-parts只有一层,我就换个思路:在$lookup
之前创建一个顶层。例如,由于您希望使用第 3 部分的客户在第 1,2 部分(共 3 个 sub-parts)下注册,因此我们的想法是将它们分组。 $lookup
之后的这种连接有点笨拙,但是如果我们使用 $lookup
之前的 car_parts
集合中的数据,我们实际上已经知道第 1、2 部分是子部分of 3. 创建一个 topLevel
临时字段,允许预先对所有部件和 sub-parts 进行分组,如果客户使用它们,他应该在这个顶级部件下注册。这让事情变得更加优雅......