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

Mongoose中按totalCoins、level排序查询指定玩家排名的方法

Mongoose实现多规则玩家排名查询

排序规则说明

排名优先级从高到低:

  1. 按totalCoins字段降序(金币越高排名越靠前)
  2. 金币相同的情况下,按level字段降序(等级越高排名越靠前)
    如果需要同分不并列,可以在最后补充次级排序规则,比如按_id升序/注册时间升序即可

前置性能优化(10w+数据必做)

提前创建匹配排序规则的复合索引,避免全表扫描和内存排序,查询耗时可以降到毫秒级:

// 在Player Schema上创建复合索引
const playerSchema = new mongoose.Schema({
  // 原有字段定义...
})
// 索引字段排序方向和查询排序方向保持一致
playerSchema.index({ totalCoins: -1, level: -1, _id: 1 })
const Player = mongoose.model('Player', playerSchema)

方案1:计数法(性能最优,推荐单玩家排名查询场景)

核心逻辑:先拿到目标玩家的金币、等级数值,统计所有排名比他高的玩家总数,最终排名 = 高排名玩家数 + 1。

async function getPlayerRank(playerId) {
  // 1. 查询目标玩家的排序字段值
  const target = await Player.findById(playerId, 'totalCoins level _id')
  if (!target) throw new Error('玩家不存在')

  // 2. 统计所有排名高于目标玩家的数量
  const higherCount = await Player.countDocuments({
    $or: [
      // 金币比目标高的,排名一定靠前
      { totalCoins: { $gt: target.totalCoins } },
      // 金币相同、等级比目标高的,排名靠前
      { totalCoins: target.totalCoins, level: { $gt: target.level } },
      // (可选)金币等级都相同,按_id升序排的话,_id更小的排名靠前,不需要并列排名就加这一条
      { totalCoins: target.totalCoins, level: target.level, _id: { $lt: target._id } }
    ]
  })

  // 3. 返回最终排名
  return higherCount + 1
}

// 调用示例:查询_id=4的玩家排名
const rank = await getPlayerRank(4)

这个方案不需要拉取全表数据排序,走索引的count操作资源消耗极低,10w-百万级数据量都适用。
按照给出的示例数据计算,_id=4的玩家用这个方案查询返回的排名是3,符合预期。


方案2:窗口函数聚合(适合连带返回排名列表场景)

如果使用MongoDB 5.0及以上版本,需要同时返回玩家信息+排名、或者需要查询某玩家前后的排名列表,可以用$setWindowFields窗口函数直接生成排名:

async function getPlayerRankWithInfo(playerId) {
  const result = await Player.aggregate([
    // 按规则排序,走提前创建的复合索引
    { $sort: { totalCoins: -1, level: -1, _id: 1 } },
    // 生成排名字段
    {
      $setWindowFields: {
        sortBy: { totalCoins: -1, level: -1, _id: 1 },
        output: {
          rank: {
            // $denseRank: 同分同名次,比如两个第3名,下一名是第4
            // $rank: 同分跳号,比如两个第3名,下一名是第5
            $denseRank: {}
          }
        }
      }
    },
    // 匹配目标玩家
    { $match: { _id: playerId } },
    // 自定义返回字段
    { $project: { name: 1, totalCoins: 1, level: 1, rank: 1 } }
  ])
  return result[0]
}

// 调用示例
const playerInfo = await getPlayerRankWithInfo(4)
// 返回结构:{ _id:4, name:'def', totalCoins:100, level:4, rank:3 }

注意:MongoDB版本低于5.0不支持窗口函数,直接用方案1即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 15:24:21