Node.js mongodb在遍历大型数据库时停止
这是此Stackoverflow问题的后续问题:。这次的转弯稍微有点不同Node.js mongodb在遍历大型数据库时停止,node.js,mongodb,Node.js,Mongodb,这是此Stackoverflow问题的后续问题:。这次的转弯稍微有点不同 在MunGDB文档上迭代时,如果目标DB大小过大,任务将停止在中间。(单个集合中有3000多个文档,每个文档都包含很长的文本,因此。由于内存限制,toArray实际上不可行。3000只是整个数据的一部分,完整数据可能超过10000个文档。)我注意到,如果集合中的文档数大于大约750,它只停留在任务的中间。 我搜索了以前的Stackoverflow问题来解决这个问题:有人说,在大型集合上迭代需要使用流,每个或映射,而不是使用
在MunGDB文档上迭代时,如果目标DB大小过大,任务将停止在中间。(单个集合中有3000多个文档,每个文档都包含很长的文本,因此
。由于内存限制,toArray
实际上不可行。3000只是整个数据的一部分,完整数据可能超过10000个文档。)我注意到,如果集合中的文档数大于大约750,它只停留在任务的中间。
我搜索了以前的Stackoverflow问题来解决这个问题:有人说,在大型集合上迭代需要使用流
,每个
或映射
,而不是使用光标
。当我在现实生活中尝试这些建议时,没有一个能奏效。它们也只是停留在中间,与<>代码> /<代码>迭代几乎没有区别。我真的不喜欢扩展timeout
的想法,因为它可能会使光标在内存中四处漂移,但也不起作用
下面的每个方法都处于async
条件下
流方法
const cursor = db.collections('mycollection').find()
cursor.on('data', doc => {
await doSomething(doc)//do something with doc here
})
while/for方法(只需将while
替换为for
)
map/each/foreach方法(将map
替换为foreach/each
)
它们之间没有任何区别。当它迭代大约750个文档时,它们就会停止,然后挂起。我甚至尝试在Promise.all
上注册每个文档,稍后立即执行async/await
任务,这样游标在迭代时不会花费太多时间,但同样的问题也会出现
编辑:我认为doSomething()
会让其他读者感到困惑。因此,我创建了一个示例代码,这样您就可以重现这个问题
const MongoClient = require('mongodb').MongoClient
const MongoUrl = 'mongodb://localhost:27017/'
const MongoDBname = 'testDB'
const MongoCollection = 'testCollection'
const moment = require('moment')
const getDB = () =>
new Promise((resolve,reject)=>{
MongoClient.connect(MongoUrl,(err,client)=>{
if(err) return reject(err)
console.log('successfully connected to db')
return resolve(client.db(MongoDBname))
client.close()
})
})
;(async ()=>{
console.log(`iteration begins on ${moment().format('YYYY/MM/DD hh:mm:ss')} ------------`)
let db = await getDB() //receives mongodb
//iterate through all db articles...
const cursor = await db.collection(MongoCollection).find()
const maxDoc = await cursor.count()
console.log('Amount of target document:' + maxDoc)
let count = 0
//replace this with stream/while/map...any other iteration methods
cursor.each((err,doc)=>{
count ++
console.log(`preloading doc No.${count} async ${(count / maxDoc * 100).toFixed(2)}%`)
})
})()
我的道歉。在试运行中。它实际上迭代了所有文档…我想我真的对其他部分做了一些错误。我将用引起麻烦的其他部分详细说明这一点。什么是doSomething()
实际在做什么?这里最大的可能性是,实际上是代码导致了问题。还要注意的是,无论是.map()
还是“stream”方法实际上都没有在每次迭代中“等待”,因为每次都缺少所需的步骤。但对于初学者来说,让我们确保即使是doSomething()
这一点也无法以更好的方式实现。也许可以,你说得对.map()
或上面的流
并不真正等待异步调用。如果引起混乱,很抱歉。但是,当我尝试在没有实际的doSomething()
的情况下,使用console.log()
或此迭代本身的任何其他测试方法对其进行调试时,进度仍然会在类似的点停止。正如我上面提到的,我甚至使用了Promise
来避免由于wait
而造成的任何延迟,但同样的问题仍然发生。我的函数可能有问题,但光标一开始甚至没有到达终点。没有“你错了”,因为两者实际上都有等待“下一次循环迭代”的方法,只是你的解释错了。我要你做的,也是解决你问题的唯一方法,就是实际“展示doSomething()
code正在做什么”。几乎可以肯定,您在代码中做了一些错误的事情,并且很可能没有等待代码中的回调或承诺。简言之,你得出了一个错误的结论,即这与“光标”有关,而这不是真正的问题。对不起,我不明白这一点。除了日志记录(console.log()
)和计数(count++
)之外,我确实删除了所有其他部分,以检查我是否对doSomething()
做了任何错误,它仍然会在类似点停止。当没有实际可用的函数时,我对函数做了什么错误????我将使用示例编辑帖子,这样您就可以在不使用doSomething()的情况下重现问题。在实际程序完成之前,您正在关闭连接client.close()
。另外,只需简单地const client=wait MongoClient.connect(MongoUrl)
,并在正常范围内执行此操作。你的整个“连接功能”基本上是有缺陷的。实际上,我给了你代码,在你的最后一个问题上清楚地显示了这一点。我建议你再复习一遍。
const cursor = db.collections('mycollection').find()
cursor.map(async doc=>{
await doSomething(doc)
})
const MongoClient = require('mongodb').MongoClient
const MongoUrl = 'mongodb://localhost:27017/'
const MongoDBname = 'testDB'
const MongoCollection = 'testCollection'
const moment = require('moment')
const getDB = () =>
new Promise((resolve,reject)=>{
MongoClient.connect(MongoUrl,(err,client)=>{
if(err) return reject(err)
console.log('successfully connected to db')
return resolve(client.db(MongoDBname))
client.close()
})
})
;(async ()=>{
console.log(`iteration begins on ${moment().format('YYYY/MM/DD hh:mm:ss')} ------------`)
let db = await getDB() //receives mongodb
//iterate through all db articles...
const cursor = await db.collection(MongoCollection).find()
const maxDoc = await cursor.count()
console.log('Amount of target document:' + maxDoc)
let count = 0
//replace this with stream/while/map...any other iteration methods
cursor.each((err,doc)=>{
count ++
console.log(`preloading doc No.${count} async ${(count / maxDoc * 100).toFixed(2)}%`)
})
})()