在一个MongoDB聚合查询中进行排序和分组

4
在一个聚合查询中同时使用$sort$group似乎表现异常。
测试数据:
db.createCollection("test");

db.test.insert({
    ts : 100,
    category : 1
});

db.test.insert({
    ts : 80,
    category : 1
});

db.test.insert({
    ts : 60,
    category : 2
});

db.test.insert({
    ts : 40,
    category : 3
});

当按ts进行排序时,一切看起来都很好,但是当我同时使用$sort$group时,结果顺序就错了。查询:

db.test.aggregate([
{
    $sort : {ts: 1}
},
{
    $group:{"_id":"$category"}
}
]);

以相反的顺序排列的结果:

{ "_id" : 1 }
{ "_id" : 2 }
{ "_id" : 3 }

是Mongo的特性还是我的误解?可能是因为Mongo首先应用分组,然后无法按缺失字段进行排序。这可能是mongoose禁止在排序时使用distinct的原因。


1
我认为如果你将聚合操作先按 "$group" 排序,然后再按 "$sort" 排序,那么就可以正常工作了:db.test.aggregate([ { $group:{"_id":"$category"} },{ $sort : {ts: 1} } ]); - Neo-coder
3个回答

5

您需要先对结果进行$group$sort。由于您只需要_id字段,因此需要使用$project阶段。

db.test.aggregate(
    [
        { "$group": { "_id": "$category" }},
        { "$sort" : { "ts": 1 }},
        { "$project": { "_id": 1 }}
    ]
);

请问一件事,当我在 $lookup 之前应用 sort 时,lookup 是否会改变顺序? - Sudhanshu Gaur

1

当你首次通过$sortts排序时,你基本上是在对集合中的所有元素进行排序。因此,如果你只运行聚合管道中的$sort阶段,你将得到以下结果:

//Query
db.test.aggregate([
    { $sort: { ts: 1} }
]);

//Output
{ "_id" : ObjectId("55141da6e4c260ae9e00832b"), "ts" : 40, "category" : 3 }
{ "_id" : ObjectId("55141d9fe4c260ae9e00832a"), "ts" : 60, "category" : 2 }
{ "_id" : ObjectId("55141d99e4c260ae9e008329"), "ts" : 80, "category" : 1 }
{ "_id" : ObjectId("55141d93e4c260ae9e008328"), "ts" : 100, "category" : 1 }

在你的代码中,当你添加$group阶段时,你基本上是通过category字段对上述结果进行分组,从而产生你得到的输出:
{ "_id" : 1 }
{ "_id" : 2 }
{ "_id" : 3 }

最终结果取决于你想要实现什么目标。
如果你想要返回按照“ts”字段过滤后的类别,你应该只使用“$sort”阶段,然后操作结果数据集:
var data = db.test.aggregate([
                    {$sort: { ts: 1}}, 
                    {$project: { 
                        _id: 0, 
                        ts: 1, 
                        category: 1
                        }
                    }
]).toArray();

for(var i = 0; i < data.length; i++) {
    console.log(data[i].category); //Output 3, 2, 1 in that sequence, on different lines
}

0
如果你想要以另一种方式进行排序,可以这样做:
db.test.aggregate([
{
    $sort : {ts: -1}
},
{
    $group:{"_id":"$category"}
}
]);

注意数字1前面的减号-

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接