具有关系的MongoDB分组聚合查询
假设我在协会收藏中有以下文档:具有关系的MongoDB分组聚合查询,mongodb,aggregation-framework,grouping,Mongodb,Aggregation Framework,Grouping,假设我在协会收藏中有以下文档: { "id" : 1, "parentId" : 1, "position" : { "x" : 1, "y" : 1 }, "tag" : "Beta" }, { "id" : 2, "parentId" : 2, "position" : { "x" : 2, "y" : 2 }, "tag" : "Alpha" },
{
"id" : 1,
"parentId" : 1,
"position" : {
"x" : 1,
"y" : 1
},
"tag" : "Beta"
},
{
"id" : 2,
"parentId" : 2,
"position" : {
"x" : 2,
"y" : 2
},
"tag" : "Alpha"
},
{
"id" : 3,
"parentId" : 1,
"position" : {
"x" : 3,
"y" : 3
},
"tag" : "Delta"
},
{
"id" : 4,
"parentId" : 1,
"position" : {
"x" : 4,
"y" : 4
},
"tag" : "Gamma"
},
{
"id" : 5,
"parentId" : 2,
"position" : {
"x" : 5,
"y" : 6
},
"tag" : "Epsilon"
}
我想创建一个聚合查询以生成以下结果:
{
"_id" : 2,
"position" : {
"x" : 2,
"y" : 2
},
"tag" : "Alpha",
"children" : [
{
"position" : {
"x" : 5,
"y" : 6
},
"tag" : "Epsilon"
}
]
},
{
"_id" : 1,
"position" : {
"x" : 1,
"y" : 1
},
"tag" : "Beta"
"children" : [
{
"position" : {
"x" : 3,
"y" : 3
},
"tag" : "Delta"
},
{
"position" : {
"x" : 4,
"y" : 4
},
"tag" : "Gamma"
}
]
}
但是,我只能创建以下分组查询,将“所有相关”文档放入子数组中:
db.association.aggregate([{
$group : {
_id : "$parentId",
children : {
$push : {
position : "$position",
tag :"$tag"
}
}
}
}])
我不知道如何筛选出特定于“父”点的“位置”和“标记”,并将它们放在顶层。通过确保文档已排序(父-子1-子2…-子n),我们可以将
分组文档
与第一个子文档(即父
)合并。在最后一步中,我们需要从子数组中删除父数组
试试这个:
db.association.aggregate([
{
$sort: {
parentId: 1,
id: 1
}
},
{
$group: {
_id: "$parentId",
children: {
$push: {
position: "$position",
tag: "$tag"
}
}
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$$ROOT",
{
$arrayElemAt: [
"$children",
0
]
}
]
}
}
},
{
$addFields: {
children: {
$slice: [
"$children",
1,
{
$size: "$children"
}
]
}
}
}
])
通过确保文档已排序(父-子1-子2…-子n),我们可以将分组文档
与第一个子文档(即父
)合并。在最后一步中,我们需要从子数组中删除父数组
试试这个:
db.association.aggregate([
{
$sort: {
parentId: 1,
id: 1
}
},
{
$group: {
_id: "$parentId",
children: {
$push: {
position: "$position",
tag: "$tag"
}
}
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$$ROOT",
{
$arrayElemAt: [
"$children",
0
]
}
]
}
}
},
{
$addFields: {
children: {
$slice: [
"$children",
1,
{
$size: "$children"
}
]
}
}
}
])
虽然瓦利乔恩的答案是有效的,但需要先对其进行排序。
这里有一个不需要排序的解决方案,但是使用stage(它非常适合实现您所需的功能)
- 第一阶段是做好这项工作李>
- 第二个用于过滤没有任何子级的文档李>
- 第三个仅用于从子数组中删除父数组。但是,如果您可以删除父级中的自引用,则不再需要最后一个阶段
虽然瓦利乔恩的答案是有效的,但需要先对其进行排序。
这里有一个不需要排序的解决方案,但是使用stage(它非常适合实现您所需的功能)
- 第一阶段是做好这项工作李>
- 第二个用于过滤没有任何子级的文档李>
- 第三个仅用于从子数组中删除父数组。但是,如果您可以删除父级中的自引用,则不再需要最后一个阶段
嘿,$graphLookup是一个选项-在这种情况下,任务比$group做得更好@Lukasz@matthpen我也想过$graphLookup
,但我一直认为*查找
到目前为止性能很差。我做了一些小的基准测试:插入170万条记录并运行:$group
、$graphLookup
和$lookup
(有3种可能的解决方案)。Robo3t执行聚合并返回前50条记录。因此,我由不同的操作员分别执行了每个解决方案,下面是执行时间:$group
:18.5秒,$graphLookup
:5.4秒和$lookup
:96.8秒浪费时间。实际上,$graphLookup
是最好的解决方案,upvotedHey,$graphLookup是一个选项-在这种情况下,任务比$group做得更好@Lukasz@matthpen我也想过$graphLookup
,但我一直认为*查找
到目前为止性能很差。我做了一些小的基准测试:插入170万条记录并运行:$group
、$graphLookup
和$lookup
(有3种可能的解决方案)。Robo3t执行聚合并返回前50条记录。因此,我由不同的操作员分别执行了每个解决方案,下面是执行时间:$group
:18.5秒,$graphLookup
:5.4秒和$lookup
:96.8秒浪费时间。确实,$graphLookup
是最好的解决方案,upvotedHey,我喜欢你的解决方案,但我不能假设我的数据会被订购,但我为你提出的解决方案给出+1,谢谢@Lukasz您可以按parentId
+id
字段排序(确保这些字段有索引)嘿,我喜欢您的解决方案,但我不能假设我的数据会被排序,但我为您建议的解决方案提供+1,谢谢@Lukasz您可以按parentId
+id
字段排序(确保这些字段有索引)