MongoDB聚合aggregation中如何按type限制同类型文档最多返回2条
实现方案
你的需求完全可以通过MongoDB标准聚合管道实现,原生$limit阶段仅支持全局固定条数限制,无法直接实现按字段分组的条数上限规则,通过管道阶段组合即可完成需求,不需要修改引擎原生逻辑。
最优实现(MongoDB 5.0+版本适用,完全匹配示例输出顺序)
用$setWindowFields给同type的文档按原始顺序编排名次,直接过滤掉每个分组内排名超过2的文档即可,不会打乱原文档的先后顺序:
db.collection.aggregate([ { $setWindowFields: { partitionBy: "$type", // 按_id排序即默认的文档入库自然顺序,有自定义排序规则可调整sortBy配置 sortBy: { _id: 1 }, output: { typeRank: { $documentNumber: {} } } } }, // 每个type最多保留2条 { $match: { typeRank: { $lte: 2 } } }, // 移除辅助排名字段 { $unset: "typeRank" } ])
运行后输出结果和你给出的期望结果完全一致:
{"type": "one"} {"type": "two"} {"type": "one"} {"type": "three"} {"type": "three"}
低版本兼容实现(MongoDB 5.0以下版本适用)
如果你的MongoDB版本低于5.0,不支持窗口函数,可以通过分组切片的方式实现:
db.collection.aggregate([ // 按type分组收集所有文档 { $group: { _id: "$type", docs: { $push: "$$ROOT" } } }, // 每个分组只取前2条文档 { $project: { docs: { $slice: ["$docs", 2] }, _id: 0 } }, // 拆分切片后的文档数组 { $unwind: "$docs" }, // 还原原始文档结构 { $replaceRoot: { newRoot: "$docs" } } ])
如果需要严格保留原始文档的输出顺序,可以在分组前先给全集合文档生成全局顺序标记,拆分完成后按全局标记排序即可还原顺序。
注意事项
- 如果不需要严格保留原始文档的输出顺序,低版本实现直接用上述分组切片逻辑即可,性能表现更好。
- 单type下的文档量如果非常大,
$group+$push的方案会产生较高的内存占用,优先升级到5.0+使用窗口函数方案,内存占用和查询性能表现都更优。
内容的提问来源于stack exchange,提问作者Mattew Silva
相关产品推荐
相关产品推荐

