MongoDB 4.2.22如何按多条件分组选取指定首条记录
适配MongoDB 4.2.22的解决方案
由于MongoDB 4.2.22不支持窗口函数,我们可以通过聚合管道多阶段组合实现需求:先按userId筛选最高mainVersion,再在该版本组内选取最小version的记录。
聚合管道实现代码
db.your_collection.aggregate([ // 阶段1:按userId分组,获取每个用户的最高mainVersion { $group: { _id: "$userId", maxMainVersion: { $max: "$mainVersion" } } }, // 阶段2:关联原集合,获取该userId下所有对应最高mainVersion的记录 { $lookup: { from: "your_collection", let: { userId: "$_id", targetMainVersion: "$maxMainVersion" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: ["$userId", "$$userId"] }, { $eq: ["$mainVersion", "$$targetMainVersion"] } ] } } } ], as: "target_records" } }, // 阶段3:展开目标记录数组 { $unwind: "$target_records" }, // 阶段4:按userId分组,对目标记录按version升序排序后取第一条(最小version) { $group: { _id: "$_id", result: { $first: { $arrayElemAt: [ { $sortArray: { input: ["$target_records"], sortBy: { version: 1 } } }, 0 ] } } } }, // 阶段5:整理输出格式,提取完整记录 { $replaceRoot: { newRoot: "$result" } } ])
步骤说明
- 阶段1:通过
$group聚合每个userId的最大mainVersion,得到用户与最高主版本的映射关系。 - 阶段2:使用
$lookup子管道精准匹配每个用户下属于最高主版本的所有记录,避免全局关联的性能损耗。 - 阶段3:
$unwind将数组形式的目标记录展开,为后续排序分组做准备。 - 阶段4:再次按
userId分组,用$sortArray对目标记录按version升序排列,再用$first取排序后的第一条(即最小version的记录)。 - 阶段5:
$replaceRoot将结果展开为原始记录格式,方便直接使用。
替代简化方案(数据量较小时适用)
如果数据集规模不大,也可以先按userId+mainVersion分组记录每组最小version,再筛选出每个用户最高mainVersion对应的记录:
db.your_collection.aggregate([ // 按userId+mainVersion分组,记录每组的最小version { $group: { _id: { userId: "$userId", mainVersion: "$mainVersion" }, minVersion: { $min: "$version" }, record: { $first: "$$ROOT" } } }, // 按userId分组,找出最高mainVersion对应的记录 { $group: { _id: "$_id.userId", targetRecord: { $max: { $cond: [ { $eq: ["$_id.mainVersion", { $max: "$_id.mainVersion" }] }, { mainVersion: "$_id.mainVersion", version: "$minVersion", originalRecord: "$record" }, null ] } } } }, // 提取原始记录 { $replaceRoot: { newRoot: "$targetRecord.originalRecord" } } ])
内容的提问来源于stack exchange,提问作者count_campeador
相关产品推荐
相关产品推荐

