mongodb - 根据关键值对文档进行排序和排名?

标签 mongodb aggregation-framework

我正在尝试为集合中的学生提取得分最高的文档,并在下面形成查询:

{ name: "Person1", marks: 20  }
{ name: "Person2", marks: 20  }
{ name: "Person1", marks: 30  }
{ name: "Person1", marks: 25  }
{ name: "Person2", marks: 50  }
{ name: "Person1", marks: 90  }
{ name: "Person3", marks: 990 }

我的查询:

db.mytest1.aggregate( [          
  { $sort : { "name" : 1,"marks" : -1} },
  {$group:
    {
      _id: "$name",
      name: { $first: "$name" },
      marks: { $first: "$marks" }
   }}
])

有更好的方法吗?

如果我的场景是根据标记对文档进行编号,我该如何实现?

我想得到以下结果:

{ name: "Person1", marks: 90,  rank: 1 }
{ name: "Person1", marks: 30,  rank: 2 }
{ name: "Person1", marks: 25,  rank: 3 }
{ name: "Person1", marks: 20,  rank: 4 }
{ name: "Person2", marks: 50,  rank: 1 }
{ name: "Person2", marks: 20,  rank: 2 }
{ name: "Person3", marks: 990, rank: 3 }

最佳答案

我真的认为这是最实用的简单游标迭代,但稍后会详细介绍。

使用聚合框架进行“小型”分组的最快实用方法是使用 MongoDB 3.2 引入的 $unwind 中的 includeArrayIndex:

db.mytest1.aggregate([
  { "$sort": { "name" : 1,"marks" : -1} },
  { "$group": {
    "_id": "$name",
    "items": { "$push": "$$ROOT" }
  }},
  { "$unwind": { "path": "$items", "includeArrayIndex": "items.rank" } },
  { "$replaceRoot": { "newRoot": "$items" } },
  { "$sort": { "name" : 1,"marks" : -1} }
])

产生:

{ "name" : "Person1", "marks" : 90, "rank" : NumberLong(0) }
{ "name" : "Person1", "marks" : 30, "rank" : NumberLong(1) }
{ "name" : "Person1", "marks" : 25, "rank" : NumberLong(2) }
{ "name" : "Person1", "marks" : 20, "rank" : NumberLong(3) }
{ "name" : "Person2", "marks" : 50, "rank" : NumberLong(0) }
{ "name" : "Person2", "marks" : 20, "rank" : NumberLong(1) }
{ "name" : "Person3", "marks" : 990, "rank" : NumberLong(0) }

或者走得更远一点:

db.mytest1.aggregate([
  { "$sort": { "name" : 1,"marks" : -1} },
  { "$group": {
    "_id": "$name",
    "items": { "$push": "$$ROOT" }
  }},
  { "$unwind": { "path": "$items", "includeArrayIndex": "items.rank" } },
  { "$project": { 
    "_id": 0, 
    "name": "$items.name", 
    "marks": "$items.marks",
    "rank": { "$add": [ "$items.rank", 1 ] } 
  }},
  { "$sort": { "name" : 1,"marks" : -1} }
])

以你想要的方式。

{ "name" : "Person1", "marks" : 90, "rank" : 1 }
{ "name" : "Person1", "marks" : 30, "rank" : 2 }
{ "name" : "Person1", "marks" : 25, "rank" : 3 }
{ "name" : "Person1", "marks" : 20, "rank" : 4 }
{ "name" : "Person2", "marks" : 50, "rank" : 1 }
{ "name" : "Person2", "marks" : 20, "rank" : 2 }
{ "name" : "Person3", "marks" : 990, "rank" : 1 }

但是要小心,因为我们将所有内容都放入一个数组中进行“分组”,以便在提取时获得“索引”位置。这适用于小型列表,但您永远不会尝试使用数千个项目。

对于 1000 项,然后迭代游标并在中断处排名:

var current = null,
    rank = 0;

db.mytest1.find().sort({ "name": 1, "marks": -1 }).forEach(doc => {
  if ( doc.name != current || current == null ) {
    rank = 0;
    current = doc.name;
  }
  rank++;
  doc.rank = rank;
  delete doc._id;
  printjson(doc);
})

这是相同的结果:

{ "name" : "Person1", "marks" : 90, "rank" : 1 }
{ "name" : "Person1", "marks" : 30, "rank" : 2 }
{ "name" : "Person1", "marks" : 25, "rank" : 3 }
{ "name" : "Person1", "marks" : 20, "rank" : 4 }
{ "name" : "Person2", "marks" : 50, "rank" : 1 }
{ "name" : "Person2", "marks" : 20, "rank" : 2 }
{ "name" : "Person3", "marks" : 990, "rank" : 1 }

实际上,您也可以这样做,因为它既简单又快速。

关于mongodb - 根据关键值对文档进行排序和排名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44587829/

相关文章:

javascript - Meteor 中的并发插入

c# - 在 Mongodb 中按日期聚合

mongodb - 如何在 MongoDB 聚合查询中使用 $hint?

javascript - MongoDB 投影将子对象作为列返回

javascript - bson的javascript/javascriptwithscope类型有什么用

javascript - Mongoose 设计模型中的嵌入式文档与引用?

node.js - 防止保存空文档

node.js - MongoDB : How to multiply a field that appears only in $project?

mongodb - 如果在数组中找不到匹配项,则返回第一个元素

c# - 快速导入 MongoDb