给定年龄指数的用户:
{ name: 'Bob',
age: 21 }
{ name: 'Cathy,
age: 21 }
{ name: 'Joe',
age: 33 }
获得输出:
[
{ _id: 21,
names: ['Bob, 'Cathy'] },
{ _id: 33,
names: ['Joe'] }
]
是否可以按年龄进行排序,分组和限制?
db.users.aggregate(
[
{
$sort: {
age: 1
}
},
{
$group : {
_id : $age,
names:{ $push: '$name' }
},
{
$limit: 10
}
]
我做了一些研究,但是不清楚是否可以先排序然后分组。在我的测试中,小组失去了那种,但我不明白为什么。
如果组保留排序,则排序和限制可以大大减少所需的处理。它只需要做足够的工作来填充"限制10组。
所以,
答案 0 :(得分:4)
要回答您的第一个问题:$group
不保留订单。有一个公开的变更请求,这些变更也突出了一些背景,但看起来产品不会被改变以保留输入文件。顺序:
一般情况下可以说两件事:您通常希望先分组,然后再进行排序。原因是排序较少的元素(分组通常产生的元素)将比排序所有输入文档更快。
其次,MongoDB将确保尽可能高效地进行排序。 documentation州:
当$ sort紧接在管道中的$ limit之前时,$ sort 操作仅在进展时保持前n个结果,其中n 是指定的限制,MongoDB只需要存储n个项目 记忆。当allowDiskUse为true时,此优化仍然适用 n项超过聚合内存限制。
因此,此代码可以完成您的工作:
collection.aggregate({
$group: {
_id: '$age',
names: { $push: '$name' }
}
}, {
$sort: {
'_id': 1
}
}, {
$limit: 10
})
编辑,点击您的评论:
我同意你说的话。进一步考虑你的逻辑,我会说:如果$group
足够智能使用索引,那么它甚至不应该在开始时需要$sort
阶段。不幸的是,它不是(还不是)。就目前的情况而言,$group
永远不会使用索引,并且它不会根据以下阶段(在这种情况下为$limit
)采取快捷方式。另请参阅此link,其中有人进行了一些基本测试。
聚合框架还很年轻所以我想,有很多工作要做,以使聚合管道更智能,更快。
StackOverflow上有答案(例如here),人们建议使用前期$sort
阶段以强制"强迫" MongoDB以某种方式使用索引。然而,这显着减慢了我的测试(使用不同随机分布的100万条样本形状记录)。
当谈到聚合管道的性能时,开始时$match
个阶段才是最有帮助的。如果您可以从一开始就限制需要通过管道的记录总数,那么这是您最好的选择 - 显然......;)