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

基于赞成票数的项目排名异常:所有项目均显示排名1

问题分析

你的calculateRank函数存在核心逻辑缺陷:聚合管道的$match阶段仅筛选了当前项目的投票数据,导致最终聚合结果里只有这一个项目。排序后它必然是第1位,所以无论该项目得票多少,返回的rank永远是1——你根本没把这个项目和其他项目的赞成票做对比。

解决方案

1. 修正排名计算逻辑

修改calculateRank函数,统计所有项目的总赞成票,再按票数降序排序,最后计算每个项目的排名(支持同票同排名的标准规则):

async function calculateRank(userVotesCollection, projectId) {
  const rankData = await userVotesCollection.aggregate([
    // 筛选所有赞成票数据
    { $match: { vote_type: "up" } },
    // 按项目分组,统计每个项目的总赞成票
    {
      $group: {
        _id: "$project_id",
        totalUpVotes: { $sum: 1 }
      }
    },
    // 按赞成票数量降序排序
    { $sort: { totalUpVotes: -1 } },
    // 使用窗口函数计算排名,支持同票同排名
    {
      $setWindowFields: {
        sortBy: { totalUpVotes: -1 },
        output: {
          rank: {
            $rank: {}
          }
        }
      }
    }
  ]).toArray();

  if (rankData.length === 0) {
    return null;
  }

  // 定位当前项目的排名
  const projectRank = rankData.find(doc => doc._id.toString() === projectId);
  return projectRank ? projectRank.rank : null;
}

2. 调整投票更新流程

原代码先计算排名再插入新投票,导致用旧数据计算排名。需要把插入投票的逻辑移到计算排名之前:

// 先保存新投票记录
const insertResult = await votesCollection.insertOne(newUserVote);
if (insertResult.insertedCount !== 1) {
  return res.status(500).json({ error: 'Failed to save vote' });
}

// 针对up类型投票,用最新数据计算并更新排名
if (vote_type === 'up') {
  const rank = await calculateRank(votesCollection, project_id);
  if (rank !== null) {
    await projectCollection.updateOne(
      { _id: new ObjectId(project_id) },
      { $set: { project_rank: rank } }
    );
  }
}

3. 补充其他高权重投票的排名更新

如果10-up、20-up这类投票也需要触发排名更新,需要在对应的分支里添加相同的排名计算逻辑。

关键说明
  • 使用$setWindowFields+$rank操作符可以高效实现标准排名规则,避免手动遍历排序的误差和性能问题。
  • 必须先插入新投票再计算排名,确保基于最新的投票数据统计相对排名。
  • 聚合时不能限制单个项目,必须统计所有项目的票数才能得到正确的排名顺序。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 05:33:11