MongoDB 使用排序查询结果中的位置来计算字段

MongoDB use position in sorted query result to compute field

我有一个供用户使用的 Mongoose 模型。每个用户都有一定数量的积分。我想创建一个用户排名字段:

rank = user position sorted by rank / total users

假设用户模型如下所示:

{
    'name': 'bob',
    'points': 15,
    'rank': 9/15,
}

(我意识到分数在存储时实际上是小数)。

有什么方法可以更新所有这些用户:

1) 按分数排序

2) 获取用户在此排序列表中的索引

3) 将该索引除以列表中的项目总数

我不确定使用哪种 mongo 运算符来查找文档在查询结果中的位置以及查找查询结果的总大小。

您可以使用几个查询和一些 JavaScript 来完成此操作。扩展您概述的步骤,您需要做的是:

  1. 找到所有用户文档,按 points 降序排列并将结果分配给游标。您可能希望确保在此字段上有一个索引以使此查询 运行 更快。
  2. 获取返回的文档数。
  3. 使用索引跟踪文档在结果中的位置。
  4. 遍历文档,使用计数和索引计算 rank,并使用计算结果更新相应用户的 rank

mongo shell 中,代码如下所示。

var c = db.user.find().sort({ "points": -1 });
var count = c.count();
var i = 1;
while (c.hasNext()) {
    var rank = i / count;
    var user = c.next();
    db.user.update(
        { "_id": user._id },
        { "$set": { "rank": rank } }
    );
    i++;
}

因此,如果您的 collection 中有以下三个用户:

{
    "_id" : ObjectId("54f0af63cfb269d664de0b4e"),
    "name" : "bob",
    "points" : 15,
    "rank" : 0
}
{
    "_id" : ObjectId("54f0af7fcfb269d664de0b4f"),
    "name" : "arnold",
    "points" : 20,
    "rank" : 0
}
{
    "_id" : ObjectId("54f0af95cfb269d664de0b50"),
    "name" : "claus",
    "points" : 10,
    "rank" : 0
}

更新后他们的文档将如下所示:

{
    "_id" : ObjectId("54f0af63cfb269d664de0b4e"),
    "name" : "bob",
    "points" : 15,
    "rank" : 0.6666666666666666
}
{
    "_id" : ObjectId("54f0af7fcfb269d664de0b4f"),
    "name" : "arnold",
    "points" : 20,
    "rank" : 0.3333333333333333
}
{
    "_id" : ObjectId("54f0af95cfb269d664de0b50"),
    "name" : "claus",
    "points" : 10,
    "rank" : 1
}

使用以前的答案不是一个好主意。每次更新 points 值后需要重新计算 rank

Mongo 版本 5.0+ 引入 $rank 聚合:

db.users.aggregate([
   {
      $setWindowFields: {
         sortBy: { points: 1 },
         output: {
            rank: {
               $rank: {}
            }
         }
      }
   }
])

会输出

{ "points": 140, "rank": 1 },
{ "points": 160, "rank": 2 },
{ "points": 170, "rank": 3 },
{ "points": 180, "rank": 4 },
{ "points": 220, "rank": 5 }