何时closuresNodejs中的MongoDB数据库连接

通过Node MongoDB本地驱动程序使用Nodejs和MongoDB。 需要检索一些文件,并进行修改,然后将其保存。 这是一个例子:

db.open(function (err, db) { db.collection('foo', function (err, collection) { var cursor = collection.find({}); cursor.each(function (err, doc) { if (doc != null) { doc.newkey = 'foo'; // Make some changes db.save(doc); // Update the document } else { db.close(); // Closing the connection } }); }); }); 

具有asynchronous性质,如果更新文档的过程花费更长时间,那么当光标到达文档的末尾时,数据库连接将closures。 并非所有更新都保存到数据库。

如果省略了db.close() ,则所有文档都会正确更新,但应用程序挂起,不会退出。

我看到一个postbuild议使用一个计数器跟踪更新数量,当回落到零,然后closures数据库。 但是我在这里做错了什么? 处理这种情况的最好办法是什么? 是否必须使用db.close()来释放资源? 还是需要打开一个新的数据库连接?

这是一个基于计数方法的潜在解决scheme(我没有testing过,没有错误陷阱,但它应该expression这个想法)。

基本策略是:获取需要更新的logging数量,asynchronous保存每条logging,成功callback,如果计数达到0(最后一次更新完成),则递减计数并closures数据库。 通过使用{safe:true}我们可以确保每个更新都成功。

mongo服务器将每个连接使用一个线程,所以a)closures未使用的连接或b)池/重用它们是很好的。

 db.open(function (err, db) { db.collection('foo', function (err, collection) { var cursor = collection.find({}); cursor.count(function(err,count)){ var savesPending = count; if(count == 0){ db.close(); return; } var saveFinished = function(){ savesPending--; if(savesPending == 0){ db.close(); } } cursor.each(function (err, doc) { if (doc != null) { doc.newkey = 'foo'; // Make some changes db.save(doc, {safe:true}, saveFinished); } }); }) }); }); 

最好使用池连接,然后在应用程序生命周期结束时,在清理函数中调用db.close():

 process.on('SIGINT', cleanup); process.on('SIGTERM', cleanup); 

请参阅http://mongodb.github.io/node-mongodb-native/driver-articles/mongoclient.html

有点旧线程,但无论如何。

我发现使用计数器可能适用于简单的情况,但在复杂的情况下可能很难。 下面是我在数据库连接空闲时closures数据库连接的解决scheme:

 var dbQueryCounter = 0; var maxDbIdleTime = 5000; //maximum db idle time var closeIdleDb = function(connection){ var previousCounter = 0; var checker = setInterval(function(){ if (previousCounter == dbQueryCounter && dbQueryCounter != 0) { connection.close(); clearInterval(closeIdleDb); } else { previousCounter = dbQueryCounter; } }, maxDbIdleTime); }; MongoClient.connect("mongodb://127.0.0.1:27017/testdb", function(err, connection)( if (err) throw err; connection.collection("mycollection").find({'a':{'$gt':1}}).toArray(function(err, docs) { dbQueryCounter ++; }); //do any db query, and increase the dbQueryCounter closeIdleDb(connection); )); 

这可以是任何数据库连接的通用解决scheme。 可以将maxDbIdleTime设置为与db查询超时或更长时间相同的值。

这不是很优雅,但我想不出一个更好的方法来做到这一点。 我使用NodeJs来运行查询MongoDb和Mysql的脚本,如果数据库连接没有正确closures,那么脚本永远挂在那里。

根据上面@mpobrien的build议,我发现asynchronous模块在这方面非常有用。 以下是我采用的示例模式:

 const assert = require('assert'); const async = require('async'); const MongoClient = require('mongodb').MongoClient; var mongodb; async.series( [ // Establish Covalent Analytics MongoDB connection (callback) => { MongoClient.connect('mongodb://localhost:27017/test', (err, db) => { assert.equal(err, null); mongodb = db; callback(null); }); }, // Insert some documents (callback) => { mongodb.collection('sandbox').insertMany( [{a : 1}, {a : 2}, {a : 3}], (err) => { assert.equal(err, null); callback(null); } ) }, // Find some documents (callback) => { mongodb.collection('sandbox').find({}).toArray(function(err, docs) { assert.equal(err, null); console.dir(docs); callback(null); }); } ], () => { mongodb.close(); } ); 

我想出了一个解决scheme,涉及这样一个柜台。 它不依赖于count()调用,也不等待超时。 在每个()中的所有文档都耗尽之后它将closures数据库。

 var mydb = {}; // initialize the helper object. mydb.cnt = {}; // init counter to permit multiple db objects. mydb.open = function(db) // call open to inc the counter. { if( !mydb.cnt[db.tag] ) mydb.cnt[db.tag] = 1; else mydb.cnt[db.tag]++; }; mydb.close = function(db) // close the db when the cnt reaches 0. { mydb.cnt[db.tag]--; if ( mydb.cnt[db.tag] <= 0 ) { delete mydb.cnt[db.tag]; return db.close(); } return null; }; 

所以每次打电话时都要使用db.each()或db.save(),您可以使用这些方法来确保数据库在工作时准备就绪,并在完成时closures。

来自OP的示例:

 foo = db.collection('foo'); mydb.open(db); // *** Add here to init the counter.** foo.find({},function(err,cursor) { if( err ) throw err; cursor.each(function (err, doc) { if( err ) throw err; if (doc != null) { doc.newkey = 'foo'; mydb.open(db); // *** Add here to prevent from closing prematurely ** foo.save(doc, function(err,count) { if( err ) throw err; mydb.close(db); // *** Add here to close when done. ** }); } else { mydb.close(db); // *** Close like this instead. ** } }); }); 

现在,假设从每个callback中的第二个到最后一个callback使得它通过mydb.open(),每个callback之前从mydb.close()….所以,当然,让我知道如果这是一个问题。

因此:在数据库调用之前放置一个mydb.open(db),并在callback的返回点或数据库调用之后(取决于调用types)放置一个mydb.close(db)。

在我看来,这种计数器应该保持在数据库对象,但这是我目前的解决方法。 也许我们可以创build一个新的对象,在构造函数中使用一个数据库,并包装mongodb函数来更好地处理closures。

这是我提出的一个解决scheme。 它避免了使用toArray,它非常简短和甜美:

 var MongoClient = require('mongodb').MongoClient; MongoClient.connect("mongodb://localhost:27017/mydb", function(err, db) { let myCollection = db.collection('myCollection'); let query = {}; // fill in your query here let i = 0; myCollection.count(query, (err, count) => { myCollection.find(query).forEach((doc) => { // do stuff here if (++i == count) db.close(); }); }); });