MongoDB中如何通过指定索引列表获取数组对应元素
按自定义索引列表从MongoDB数组提取元素的实现方法
要实现从数组中按指定索引列表提取对应元素的需求,可根据使用的MongoDB版本选择对应实现方案:
方案1:MongoDB 4.4+ 最优实现(性能最优)
核心逻辑是直接遍历传入的索引列表,逐次从原数组中取出对应位置的元素,全程无额外文档拆分操作,性能开销最低。
对应的聚合管道写法:
db.collection.aggregate([ { $project: { words: { // 遍历传入的目标索引列表,本例为[0,2,5] $map: { input: [0, 2, 5], as: "currentIdx", in: { // 按当前索引值,从原words数组中提取对应元素 $arrayElemAt: ["$words", "$$currentIdx"] } } } } } ])
执行完成后输出的结果完全符合预期:
{ "words": ["a", "c", "f"] }
注意事项:
- 该写法会严格按照传入索引列表的顺序返回结果,哪怕索引顺序是打乱的(比如传入
[5,0,2],会按顺序返回["f","a","c"])- 如果传入的索引值超出原数组的长度范围,对应位置会返回
null,如果需要过滤这类无效值,可以在$map外层嵌套一层$filter,把值为null的条目移除
方案2:低版本MongoDB兼容实现(适配3.2+全版本)
如果使用的MongoDB版本低于4.4,无法在$map中直接访问文档字段和外部变量,可以通过数组拆分、筛选、重组的逻辑实现:
db.collection.aggregate([ // 拆分原words数组,同时记录每个元素在原数组中的下标 { $unwind: { path: "$words", includeArrayIndex: "originalArrayIdx" } }, // 筛选出下标在目标索引列表内的元素 { $match: { originalArrayIdx: { $in: [0, 2, 5] } } }, // 因为$match返回的元素顺序和原数组一致,这里按原下标排序,保证顺序匹配 { $sort: { originalArrayIdx: 1 } }, // 把筛选后的元素重新聚合为新数组 { $group: { _id: "$_id", words: { $push: "$words" } } } ])
注意事项:
- 这种写法因为涉及数组拆分、匹配、排序、重组几个阶段,当文档量较大、原数组长度较长时,性能会明显低于第一种
$map的实现- 如果需要严格按照传入索引列表的顺序返回结果(比如传入
[5,0,2]需要返回["f","a","c"]),该方案需要额外给每个索引标记传入时的顺序值,再按这个顺序值排序,否则返回的结果会始终按原数组的索引升序排列,无法匹配自定义的索引顺序。
内容的提问来源于stack exchange,提问作者Jinshuai Ma
相关产品推荐
相关产品推荐

