MongoDB聚合查询:展开数组并筛选指定元素及后续内容
解决方案
方法一:基于现有聚合阶段补充处理
要是你已经做完了$match、$unwind、$project拿到所有展开的元素,可以按下面的步骤补充阶段:
修改$unwind阶段,保留数组索引
把你的$unwind改成带includeArrayIndex的版本,这样每个展开的文档会多一个字段记录它在原数组中的位置:{ $unwind: { path: "$locations", includeArrayIndex: "loc_index" } }比如原数组里
uuid: '3-3'对应的loc_index是2(数组索引从0开始算)。筛选目标元素
先把所有元素分组,找到3-3对应的索引值,再筛选出索引大于等于这个值的元素,最后整理格式:// 分组获取目标索引和所有元素 { $group: { _id: "$_id", targetIndex: { $max: { $cond: [{ $eq: ["$locations.uuid", "3-3"] }, "$loc_index", -1] } }, items: { $push: { location: "$locations", index: "$loc_index" } } } }, // 重新展开元素 { $unwind: "$items" }, // 只保留索引>=目标值的元素 { $match: { $expr: { $gte: ["$items.index", "$targetIndex"] } } }, // 整理成需要的输出格式 { $project: { _id: 0, location: "$items.location" } }
方法二:优化聚合流程(更高效)
没必要先展开所有元素再筛选,直接在处理数组阶段就截取从3-3开始的片段,性能更好:
db.collection.aggregate([ // 你的$match筛选条件,比如匹配_id: '123' { $match: { _id: '123' } }, // 截取从'3-3'开始的数组部分 { $addFields: { targetLocations: { $slice: [ "$locations", { $indexOfArray: ["$locations.uuid", "3-3"] }, { $size: "$locations" } ] } } }, // 展开截取后的数组 { $unwind: "$targetLocations" }, // 输出成目标格式 { $project: { _id: 0, location: "$targetLocations" } } ])
这里先用$indexOfArray找到3-3在数组里的位置,再用$slice把从这个位置到末尾的元素切出来,之后再展开和格式化,全程只处理需要的元素,比先展开所有再筛选高效得多。
内容的提问来源于stack exchange,提问作者Ivan Bacher
相关产品推荐
相关产品推荐

