我有以下简单的node.js应用程序,它从查询创建游标,按城市排序collectoin然后温度。之后,我迭代游标并通过添加最高:true来更新每个城市的最高温度的每个文档。
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/temp', function(err, db) {
if(err) throw err;
var cursor = db.collection('data').find().sort( { City : 1, Temperature : -1 } );
var previous = '';
cursor.each(function(err, doc) {
if(err) throw err;
if(doc == null) {
console.dir("Closing database connection");
return db.close();
}
if (previous != doc.City) {
previous = doc.City;
var query = { _id : doc._id };
var operator = { '$set' : { highest : true } };
console.dir(doc.City + " is " + doc.Temperature + "; ");
db.collection('data').update(query, operator, function(err, updated) {
if(err) {
console.error('Error:', err);
throw err;
}
console.dir("Successfully updated: " + JSON.stringify(updated));
});
}
});
});
这里的问题是只有第一个城市正确更新,这是输出:
'柏林是81; ''成功更新:1''佛罗里达州巴黎是83; “ '华沙新墨西哥州是57; “巴塞罗那佛蒙特州是57岁; ''结束 数据库连接'错误:{[MongoError:连接关闭 应用程序]名称:'MongoError'}错误:{[MongoError:Connection 按应用程序关闭]名称:'MongoError'}错误:{[MongoError: 连接按应用程序关闭]名称:'MongoError'}
我对正在发生的事情的猜测是:光标通过所有文档调用更新温度最高的那些:
db.collection('data').update(query, operator, function(err, updated)
但在回调返回之前,游标完成迭代,调用这段代码关闭连接:
if(doc == null) {
console.dir("Closing database connection");
return db.close();
}
之后,所有未完成处理的更新都会因为没有数据库连接可用而出错。
处理它的正确方法是什么,只有在所有文档成功更新后才能关闭连接?
答案 0 :(得分:2)
正如Neil所提到的,我们可以使用.stream(),但是我能够通过计算已经处理的更新并在我们期望更新的所有文档都更新后计算已经处理的数据连接来按预期执行程序。 在我的情况下,它非常简单,因为我在数据库中只有4个城市,所以我希望只更新4个文档。我们也可以通过查询和计算结果来获得这个数字,但这对我来说已经足够了。
这是工作代码:
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect('mongodb://localhost:27017/temp', function(err, db) {
if(err) throw err;
var cursor = db.collection('data').find().sort( { City : 1, Temperature : -1 } );
var previous = '';
var updatedCount = 0;
var expectedToUpdate = 4; // Hardcoded, but we might want to obtain it pragmatically
cursor.each(function(err, doc) {
if(err) throw err;
if(doc == null) {
return
}
if (previous != doc.City) {
previous = doc.City;
var query = { _id : doc._id };
var operator = { '$set' : { highest : true } };
console.dir(doc.City + " is " + doc.Temperature + "; ");
db.collection('data').update(query, operator, function(err, updated) {
if(err) {
console.error('Error:', err);
throw err;
}
console.dir("Successfully updated: " + JSON.stringify(updated));
updatedCount++;
if (updatedCount == expectedToUpdate) {
console.dir("updated expected number of documents. Closing db.");
db.close();
}
});
}
});
});
答案 1 :(得分:1)
我经常发现node stream接口是迭代器的更好选择。在游标对象上有一个.stream()
方法:
var stream = db.collection('data').find().sort(
{ City : 1, Temperature : -1 }
).stream();
stream.on('data',function(data) {
// do things with current document
// but pause on things with a callback then resume;
stream.pause();
db.collection('data').update(query, operator, function(err, updated) {
// resume the stream when this callback is done
stream.resume();
})
});
stream.on('end',function() {
// Called when everything is complete
// db.close is safe here as long as you are no longer using the connection
db.close();
});
实际上,从本地驱动程序的version 2.0开始,流接口是默认游标对象的一部分。
但一般来说,只需要为一个处理脚本调用db.close()
。您通常不应该在服务器类型实现中调用它,只是在生命周期中打开连接。