Node+Express中用Mongoose按用户分组查询最佳分数及分页
解决方案:获取每个用户的最佳分数并支持分页
这个需求完全可以通过MongoDB的聚合框架实现,以下是具体的Mongoose查询方案:
1. 核心聚合查询逻辑
我们可以通过先全局排序,再分组取每组第一条的方式,得到每个用户符合规则的最佳分数:
const bestScoresPerUser = await ScoreModel.aggregate([ // 第一步:按指定规则全局排序,确保每个用户的最佳分数排在该用户所有记录的最前面 { $sort: { milliseconds: 1, // 优先按耗时升序(越小越好) flips: -1, // 耗时相同则按翻转次数降序(越大越好) _id: 1 // 前两者都相同则按文档插入顺序(_id升序) } }, // 第二步:按userId分组,取每组的第一条文档(即该用户的最佳分数) { $group: { _id: "$userId", bestScore: { $first: "$$ROOT" } // 保留整条文档,也可以单独提取需要的字段 } }, // 可选:重新整理输出格式,把userId从_id里拿出来 { $project: { _id: 0, userId: "$_id", flips: "$bestScore.flips", milliseconds: "$bestScore.milliseconds", updatedAt: "$bestScore.updatedAt", scoreId: "$bestScore._id" } } ]);
逻辑说明:
- 先通过
$sort把所有记录按规则排序,这样每个用户的最佳分数会排在该用户所有记录的最前面; - 再用
$group按userId分组,通过$first取每组的第一条文档,就是该用户的最佳分数; - 最后用
$project可以按需调整输出字段,让返回结果更简洁。
2. 分页实现
聚合查询支持分页,只需在上述聚合管道的末尾添加$skip和$limit阶段即可:
const page = 1; // 当前页码 const pageSize = 10; // 每页条数 const paginatedBestScores = await ScoreModel.aggregate([ // 前面的$sort、$group、$project阶段保持不变 { $sort: { milliseconds: 1, flips: -1, _id: 1 } }, { $group: { _id: "$userId", bestScore: { $first: "$$ROOT" } } }, { $project: { _id: 0, userId: "$_id", flips: "$bestScore.flips", milliseconds: "$bestScore.milliseconds" } }, // 添加分页阶段 { $skip: (page - 1) * pageSize }, { $limit: pageSize } ]);
额外优化:
如果需要对分页后的结果再排序(比如按最佳分数的耗时排序展示),可以在$skip之前添加一个额外的$sort阶段,比如:
// 在$skip前添加,按最佳耗时升序展示分页结果 { $sort: { milliseconds: 1 } }
内容的提问来源于stack exchange,提问作者K. Efkas
相关产品推荐
相关产品推荐

