如何用Sequelize实现排行榜用户去重,避免同一用户重复显示?
解决排行榜重复显示同一用户的问题
你需要实现每个用户仅展示其最高分数的排行榜,下面提供两种可行方案:
方案一:在Sequelize查询层面直接获取用户最高分(推荐)
通过聚合查询+分组,直接从数据库拿到每个用户的最高分数,避免后续冗余数据处理:
首先确保你已引入Sequelize实例(比如从项目模型文件中导出),然后修改查询代码:
const sequelize = require('../models').sequelize; // 根据你的项目路径调整 router.get('/leaderboard', async (req, res) => { try { const scoreDataRaw = await Score.findAll({ attributes: [ [sequelize.fn('MAX', sequelize.col('score')), 'topScore'], 'userId' ], include: [ { model: User, attributes: ['username'] } ], group: ['userId', 'User.id'], // 按用户ID分组,需包含关联模型ID避免分组报错 order: [ [sequelize.fn('MAX', sequelize.col('score')), 'DESC'] // 按最高分降序,符合排行榜逻辑 ] }); const scoreData = scoreDataRaw.map((score) => score.get({ plain: true })); // 注意此时每条数据的分数字段为topScore,模板渲染时需对应调整 res.render('leaderboard', { scoreData }); } catch (error) { res.status(500).json(error); } });
注意:原代码中order: [['score', 'ASC']]是按分数升序(从低到高),和你注释的“descending”(降序)不符,方案中已修正为降序逻辑。
方案二:在JavaScript层面过滤重复用户
如果不想修改数据库查询逻辑,可以在拿到全量分数数据后,通过JS筛选每个用户的最高分条目:
router.get('/leaderboard', async (req, res) => { try { const scoreDataRaw = await Score.findAll({ include: [ { model: User, attributes: ['username'] } ], order: [ ['score', 'DESC'] // 先按分数降序,方便后续筛选 ] }); const scoreData = scoreDataRaw.map((score) => score.get({ plain: true })); // 过滤每个用户仅保留最高分的条目 const userScoreMap = {}; scoreData.forEach(item => { const userId = item.userId; if (!userScoreMap[userId] || item.score > userScoreMap[userId].score) { userScoreMap[userId] = item; } }); // 转换为数组并保持分数降序排列 const filteredScoreData = Object.values(userScoreMap).sort((a, b) => b.score - a.score); res.render('leaderboard', { scoreData: filteredScoreData }); } catch (error) { res.status(500).json(error); } });
两种方案对比:方案一通过数据库聚合查询,性能更优(尤其数据量大时);方案二无需调整查询逻辑,适合快速迭代场景。
内容的提问来源于stack exchange,提问作者Spawze
相关产品推荐
相关产品推荐

