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

Sort and Group in one MongoDB aggregation query

在一个聚合查询中使用 $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功能还是我的误会? Maby mongo 首先应用分组,然后不能按缺失字段排序。由于这个原因,可能 mongoose 禁止在排序时使用 distinct。

如果你想按其他方式排序,可以这样做:

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

注意 1.

前面的 -

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

db.test.aggregate(
    [
        { "$group": { "_id": "$category" }},
        { "$sort" : { "ts": 1 }},
        { "$project": { "_id": 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 }

最终这一切都取决于你想要达到的目标。

如果你想return由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
}