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

Mongoose查询优化:获取唯一用户的最优成绩排行榜

解决Mongoose排行榜中用户去重并保留最优成绩的问题

这个问题确实很常见——做答题排行榜时,肯定不想让同一个用户霸榜对吧?你的需求核心是每个用户只保留其最优成绩(分数最高,同分则用时最短),然后取前10个不同的用户。用普通的find()+sort()+limit()确实搞不定,得用MongoDB的聚合管道来实现,我给你一步步拆解:

实现思路

我们需要通过四个聚合阶段来达成目标:

  1. 全局预排序:先把所有文档按「分数降序、用时升序」排列,这样每个用户的最优成绩会排在该用户所有文档的最前面。
  2. 按用户分组:以userId为分组依据,提取每组的第一个文档(也就是该用户的最优成绩)。
  3. 最终排序:对分组后的结果再次按「分数降序、用时升序」排序,确保排行榜的顺序完全符合规则。
  4. 限制数量:取前10个用户的最优成绩。

完整代码示例

const topUsers = await QuizModel.aggregate([
  // 1. 全局排序:让每个用户的最优成绩排在该用户文档的最顶部
  {
    $sort: {
      "result.score": -1, // 分数从高到低
      "result.time": 1    // 用时从短到长
    }
  },
  // 2. 按userId分组,取每组第一个文档(即该用户的最优成绩)
  {
    $group: {
      _id: "$userId", // 分组键:userId
      quizId: { $first: "$quizId" }, // 保留该用户最优成绩的quizId
      userId: { $first: "$userId" }, // 保留userId字段
      result: { $first: "$result" }  // 保留完整的result对象
    }
  },
  // 3. 对分组后的结果再次排序,确保排行榜顺序正确
  {
    $sort: {
      "result.score": -1,
      "result.time": 1
    }
  },
  // 4. 取前10个用户
  {
    $limit: 10
  },
  // 可选:移除自动生成的_id字段,让输出更干净
  {
    $project: {
      _id: 0
    }
  }
]);

为什么这个方案可行?

拿你给出的例子验证:

  • User1的5条文档经过第一步排序后,score:100的文档会排在最前面;
  • User2的5条文档排序后,score:95的文档排在最前面;
  • 分组阶段会分别提取User1和User2的第一条文档,得到两个唯一用户的最优成绩;
  • 最终排序后,User1的成绩会排在User2前面,完全符合你的期望输出。

额外说明

  • 如果你的数据集很大,建议给userId、result.score、result.time建立复合索引,能大幅提升聚合操作的性能;
  • 如果你需要保留更多原文档的字段,只需要在$group阶段用$first添加对应的字段即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 18:27:49