回答你的第一个问题:$group
does not保留订单。有一个开放的更改请求,这些更改也稍微突出了背景,但看起来不会更改产品以保留输入文档的顺序:
- https://jira.mongodb.org/browse/SERVER-24799
- https://jira.mongodb.org/browse/SERVER-4507
- https://jira.mongodb.org/browse/SERVER-21022
一般可以说两件事:您通常希望先进行分组,然后再进行排序。原因是对较少的元素(分组通常产生的)进行排序将比对所有输入文档进行排序更快。
其次,MongoDB 将确保尽可能高效且尽可能少地进行排序。这文档 states:
当管道中 $sort 紧邻 $limit 之前时,$sort
操作仅在进行时保留前 n 个结果,其中 n
是指定的限制,MongoDB只需要存储n个项目
记忆。当allowDiskUse为true并且
n 个项目超出了聚合内存限制。
所以这段代码可以完成您的情况:
collection.aggregate({
$group: {
_id: '$age',
names: { $push: '$name' }
}
}, {
$sort: {
'_id': 1
}
}, {
$limit: 10
})
EDIT根据您的评论:
我同意你说的。进一步考虑你的逻辑,我什至会说:如果$group
足够聪明,可以使用索引,那么它甚至不需要$sort
开始时的阶段。不幸的是,它不是(还可能不是)。就今天的情况来看,$group
永远不会使用索引,也不会根据以下阶段走捷径($limit
在这种情况下)。另请参阅此link有人进行了一些基本测试。
聚合框架还很年轻,所以我想,为了使聚合管道更智能、更快速,还有很多工作要做。
StackOverflow 上有答案(例如here)人们建议使用预先$sort
阶段以“强制”MongoDB 以某种方式使用索引。然而,这显着减慢了我的测试速度(使用不同随机分布的样本形状的 100 万条记录)。
当谈到聚合管道的性能时,$match
开始的阶段才是真正有帮助的。如果您可以从一开始就限制需要通过管道的记录总量,那么这就是您最好的选择 - 显然......;)