使用mongosh的cursor.forEach()时,能否获取元素迭代索引?
MongoDB游标forEach无法获取迭代序号的解决方法
问题背景
习惯使用ES5数组的array.forEach((elem, i) => ...)语法获取元素索引,但MongoDB游标(Cursor)的forEach()方法并不支持传入索引参数——游标并非数组,官方文档对该方法的说明也较为简略。已知可以通过cursor.toArray().forEach()实现,但担心该方式会将所有文档加载到内存,导致性能下降,属于多余步骤。
测试代码(无输出):
db.collection.find().forEach((doc, i) => { if ((i == 0) || (i % 50 == 0)) { console.log(`we are here: ${i}`); // 无任何输出 } })
解决方案
MongoDB的cursor.forEach()确实没有内置传递迭代序号的机制,以下是两种无需转换为数组的高效解决方案:
1. 手动维护计数器
这是最简单直接的方案,遍历前初始化一个计数器变量,每次迭代时更新并使用它,不会产生额外性能开销:
let index = 0; db.collection.find().forEach((doc) => { if (index === 0 || index % 50 === 0) { console.log(`we are here: ${index}`); } index++; });
2. 使用聚合查询生成序号(MongoDB 4.4+)
如果需要将序号作为文档的一部分处理,可以利用MongoDB 4.4新增的$setWindowFields聚合阶段,结合$documentNumber操作符在查询阶段直接为每个文档生成全局序号,之后遍历游标时直接读取该字段:
db.collection.aggregate([ { $setWindowFields: { partitionBy: {}, // 不分区,对所有文档全局计数 sortBy: { _id: 1 }, // 指定排序字段,保证序号顺序稳定 output: { index: { $documentNumber: {} } // 生成从1开始的序号 } } } ]).forEach((doc) => { // 注意$documentNumber从1开始,所以判断条件调整为index === 1或index%50===0 if (doc.index === 1 || doc.index % 50 === 0) { console.log(`we are here: ${doc.index}`); } });
方案对比
- 手动计数器:零额外开销,实现简单,适合仅在遍历过程中需要序号的场景。
- 聚合生成序号:适合需要将序号与文档绑定的场景,但依赖MongoDB 4.4及以上版本,且会增加聚合查询的少量开销。
内容的提问来源于stack exchange,提问作者amota
相关产品推荐
相关产品推荐

