You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MongoDB聚合查询中为指定用户添加积分排名字段?

问题:为MongoDB聚合结果添加用户排名字段

现有MongoDB的Users和Points集合数据如下:

Users集合数据

{
  _id: ObjectId("62a2a0422ec90fea68390aaa"),
  name: 'Robert Yamashita',
  username: 'robyama',
  email: 'robert.yamashita@rocketmail.com',
},
{
  _id: ObjectId("62a2a0452ec90fea68390aad"),
  name: 'Charles X',
  username: 'cvx',
  email: 'charles.xxx@rocketmail.com',
}

Points集合数据

{
  userId: ObjectId("62a2a0422ec90fea68390aaa"),
  action: 'Liked a post',
  points: 10,
}
{
  userId: ObjectId("62a2a0422ec90fea68390aaa"),
  action: 'Liked a post',
  points: 10,
}
{
  userId: ObjectId("62a2a0452ec90fea68390aad"),
  action: 'Liked a comment',
  points: 5,
}

原聚合查询用于获取用户robyama的总积分,但需要补充rank字段(Robert积分20排第1,Charles积分5排第2),原查询及结果如下:

原聚合查询

db.users.aggregate([
  { $match: { username: 'robyama' } },
  {
    $lookup: {
      from: 'points',
      localField: '_id',
      foreignField: 'user', // 注意:此处原查询存在错误,Points集合关联字段为userId
      as: 'userPoints'
    }
  },
  { $unwind: '$userPoints' },
  {
    $group: {
      _id: {
        name: '$name',
        email: '$email',
        username: '$username',
      },
      count: { $sum: '$userPoints.points' }
    }
  }
]);

原查询结果

{
  "_id": {
    "name": "Robert Yamashita",
    "email": "robert.yamashita@rocketmail.com",
    "username": "robyama",
  },
  "count": 20
}

期望输出

{
  "_id": {
    "name": "Robert Yamashita",
    "email": "robert.yamashita@rocketmail.com",
    "username": "robyama",
  },
  "count": 20,
  "rank": 1
}

解决方案:修改聚合管道

要实现排名,需先统计所有用户的总积分并排序,再为目标用户匹配排名,具体调整如下:

完整修正后的聚合管道

db.users.aggregate([
  // 1. 修正关联字段,正确关联Points集合
  {
    $lookup: {
      from: 'points',
      localField: '_id',
      foreignField: 'userId',
      as: 'userPoints'
    }
  },
  // 2. 展开用户积分记录
  { $unwind: '$userPoints' },
  // 3. 按用户分组计算总积分
  {
    $group: {
      _id: {
        name: '$name',
        email: '$email',
        username: '$username',
      },
      count: { $sum: '$userPoints.points' }
    }
  },
  // 4. 按总积分降序排序
  { $sort: { count: -1 } },
  // 5. 使用窗口函数计算用户排名(从1开始)
  {
    $setWindowFields: {
      sortBy: { count: -1 },
      output: {
        rank: { $rank: {} }
      }
    }
  },
  // 6. 最后筛选目标用户robyama
  { $match: { "_id.username": 'robyama' } }
]);

关键调整说明

  1. 修正$lookup关联字段:将原查询中错误的foreignField: 'user'改为userId,确保关联逻辑正确。
  2. 移除初始$match:必须先统计所有用户的积分总和,才能计算正确排名,不能一开始就过滤单个用户。
  3. 添加$sort和$setWindowFields:
    • $sort按总积分降序排列,确保排名顺序正确;
    • $setWindowFields(MongoDB 5.0+支持)通过$rank函数生成排名,若需要连续排名(忽略并列情况),可改用$denseRank。
  4. 最后筛选目标用户:在计算完所有用户排名后,再筛选出robyama的结果。

内容的提问来源于stack exchange,提问作者The Bassman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 12:45:44