在一个 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 }}
]
);
当您第一次 $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 }
最终这一切都取决于你想要达到的目标。
如果你想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
}
在一个聚合查询中使用 $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 }}
]
);
当您第一次 $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 }
最终这一切都取决于你想要达到的目标。
如果你想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
}