用例如下。
设备包含零个或多个由device_id链接的组件
每个组件都有自己的组件,由parent_id
链接预期结果:
[
{
id: 1
name: "device_a",
components: [
{
name: "component_a",
id: 2
device_id: 1
components: [
{
name: "component_b"
parent_id: 2
id: 3
}
]
}
]
}
]
使用新的聚合框架,我可以递归地获得设备组件的深度1结果。 (备注:parent_id为null,表示组件没有父组件)
db.device.aggregate(
[
{ "$graphLookup": {
"from": "component",
"startWith": "$_id",
"connectFromField": "_id",
"connectToField": "device_id",
"as": "components",
"restrictSearchWithMatch": { "parent_id": null }
}},
{ "$addFields": {
"components": {
"$reverseArray": "$components"
}
}}
]
)
此查询结果显示输出。
[
{
id: 1
name: "device_a",
components: [
{
name: "component_a",
id: 2
device_id: 1
}
]
}
]
基本上,我也可以聚合组件本身并获得具有相同逻辑的子组件列表。
db.component.aggregate(
[
{ "$match": { "parent_id": null } },
{ "$graphLookup": {
"from": "component",
"startWith": "$_id",
"connectFromField": "_id",
"connectToField": "parent_id",
"as": "components"
}},
{ "$addFields": {
"components": {
"$reverseArray": "$components"
}
}}
]
)
/* turns out */
[
{
name: "component_a",
id: 2
device_id: 1
components: [
{
name: "component_b",
parent_id: 2
id: 3
}
]
}
]
有没有什么好方法可以将它们组合在一起?对于更高级的用例,它如何更深入,如component_a - > component_b - > component_c ...
答案 0 :(得分:0)
我想我可以生成那种形状的东西,虽然它很复杂......
> db.devices.find()
{ "_id" : 1, "name" : "device_a", "component_ids" : [ 2, 4 ] }
> db.components.find().sort({parent_id: 1})
{ "_id" : 2, "name" : "component_a", "device_id" : 1 }
{ "_id" : 4, "name" : "component_e", "device_id" : 1 }
{ "_id" : 3, "name" : "component_b", "parent_id" : 2 }
{ "_id" : 0, "name" : "component_c", "parent_id" : 2 }
{ "_id" : 1, "name" : "component_d", "parent_id" : 3 }
{ "_id" : 5, "name" : "component_f", "parent_id" : 4 }
> function getFilterForDepth(i) { return {$filter: {input: "$components.sub_components", cond: {$eq: ["$$this.depth", NumberLong(i)]}}}; }
> getFilterForDepth(0)
{
"$filter" : {
"input" : "$components.sub_components",
"cond" : {
"$eq" : [
"$$this.depth",
NumberLong(0)
]
}
}
}
> db.devices.aggregate([
{
$lookup: {
from: "components",
localField: "component_ids",
foreignField: "_id",
as: "components"
}
},
{$unwind: "$components"},
{$match: {"components.parent_id": null}},
{
$graphLookup: {
from: "components",
startWith: "$components._id",
connectFromField: "_id",
connectToField: "parent_id",
as: "components.sub_components",
depthField: "depth",
maxDepth: 2
}
},
{
$addFields: {
"components.components": {
$map: {
input: getFilterForDepth(0),
in : {
_id: "$$this._id",
name: "$$this.name",
components: {
$map: {
input: getFilterForDepth(1),
in : {_id: "$$this._id", name: "$$this.name"}
}
}
}
}
}
}
},
{$project: {"components.sub_components": 0}},
{$group: {_id: "$_id", name: {$first: "$name"}, components: {$push: "$components"}}}
])
.pretty();
{
"_id" : 1,
"name" : "device_a",
"components" : [
{
"_id" : 2,
"name" : "component_a",
"device_id" : 1,
"components" : [
{
"_id" : 0,
"name" : "component_c",
"components" : [
{
"_id" : 1,
"name" : "component_d"
}
]
},
{
"_id" : 3,
"name" : "component_b",
"components" : [
{
"_id" : 1,
"name" : "component_d"
}
]
}
]
},
{
"_id" : 4,
"name" : "component_e",
"device_id" : 1,
"components" : [
{
"_id" : 5,
"name" : "component_f",
"components" : [ ]
}
]
}
]
}
这只能达到一定的深度(我做了2,因为它更容易),并且不是自然可扩展的,但似乎可以解决问题。