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

时间:2015-03-26 12:54:12

标签: mongodb sorting mongoose mongodb-query aggregation-framework

在一个聚合查询中使用$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进行排序。

3 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:0)

如果你想以另一种方式排序,可以这样做:

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

注意1之前的-

答案 2 :(得分:0)

当您$sort ts时,您基本上是对您馆藏中的所有元素进行排序。因此,如果您只在聚合管道中运行$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
}