MongoDB聚合查询中如何结合分页实现基于review_count的排名?
为MongoDB聚合查询的分页结果添加基于review_count的item_rank
现有查询与数据结构
当前已实现排序和分页的MongoDB聚合查询如下:
db.user_stats.aggregate([ {"$match":{"company_id":5}}, {"$group":{ "_id":"$item_id", "review_count":{"$sum":"$review_count"}, "avg_rating":{"$avg":"$avg_rating"}, "item_id":{"$first":"$item_id"}, "item_type":{"$first":"$item_type"}, "company_id":{"$first":"$company_id"}, "object_id":{"$first":"$_id"} }}, {"$skip":0}, {"$limit":20}, {"$sort":{"review_count":1}} ])
数据存储结构示例:
{ "_id": {"$oid": "639c7103e687877baf0b2f57"}, "review_count": 1, "avg_rating": 4, "item_id": 2, "item_type": "user", "company_id": 5, "created_date": "2022-12-16 11:47:01" }, { "_id": {"$oid": "639c7103e687877baf0b2f57"}, "review_count": 10, "avg_rating": 4, "item_id": 2, "item_type": "user", "company_id": 5, "created_date": "2022-12-16 11:47:01" }
需求说明
需要为分页后的每条记录添加基于review_count排序的item_rank(支持并列排名,即相同review_count的记录排名一致),同时输出包含总条数、当前页码、总页数的结构化结果,格式示例:
"items": { "totalCount": 2, "current": 1, "totalPages": 1, "data": [ { "id": "639c7103e687877baf0b2f57", "item_id": 2, "item_type": "team", "item_title": "Team1", "item_rank": 2 }, { "id": "639c7103e687877baf0b2f51", "item_id": 23, "item_type": "team", "item_rank": 2 } ] }
解决方案
调整聚合阶段顺序,通过$setWindowFields计算排名,并用$facet同时处理统计与分页数据:
db.user_stats.aggregate([ // 过滤目标公司数据 {"$match":{"company_id":5}}, // 按item_id分组聚合 {"$group":{ "_id":"$item_id", "review_count":{"$sum":"$review_count"}, "avg_rating":{"$avg":"$avg_rating"}, "item_id":{"$first":"$item_id"}, "item_type":{"$first":"$item_type"}, "company_id":{"$first":"$company_id"}, "object_id":{"$first":"$_id"} }}, // 先排序,保证分页逻辑正确 {"$sort":{"review_count":1}}, // 同时处理统计和分页数据 {"$facet":{ "totalCount": [{"$count": "value"}], "data": [ {"$skip":0}, {"$limit":20}, // 计算并列排名(相同review_count排名一致) {"$setWindowFields":{ "partitionBy": null, "sortBy": {"review_count":1}, "output": { "item_rank": {"$denseRank": {}} // 若需跳跃式排名,替换为"$rank": {} } }}, // 调整字段匹配期望格式 {"$project":{ "id": "$object_id", "item_id": 1, "item_type": 1, "review_count": 1, "avg_rating": 1, "item_rank": 1, "_id": 0 }} ] }}, // 整理输出结构,计算总页数 {"$project":{ "totalCount": {"$arrayElemAt": ["$totalCount.value", 0]}, "current": 1, // 可根据skip值动态计算,如skip=20则current=2 "totalPages": {"$ceil": {"$divide": [{"$arrayElemAt": ["$totalCount.value", 0]}, 20]}}, "data": "$data" }}, // 包裹到items字段 {"$project":{ "items": "$$ROOT" }} ])
关键说明
- 排序阶段前置:将
$sort移至$skip/$limit之前,确保分页基于排序后的完整数据集,避免逻辑错误。 - 排名计算:
$denseRank实现连续并列排名,相同review_count的记录排名一致;若需跳跃式排名(如1,2,2,4),改用$rank。 $facet优化查询:一次聚合同时完成总数统计和分页数据处理,减少数据库交互次数。- 字段适配:通过
$project调整字段名与结构,完全匹配需求输出格式。
内容的提问来源于stack exchange,提问作者Jitender Thakur
相关产品推荐
相关产品推荐

