在遍历光标和更新文档时,连接因应用程序错误而关闭
Connection closed by application error when iterating through cursor and updating documents
我有以下简单的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:连接关闭者Application]名称:'MongoError'}错误:{[MongoError:ConnectionClosed By Application]name:'MongoError'}错误:{[MongoError:连接已由应用程序关闭]名称:"MongoError"}
我对发生的事情的猜测是:光标遍历所有文档,调用温度最高的文档的更新:
db.collection('data').update(query, operator, function(err, updated)
但在回调返回之前,游标完成迭代,并调用此代码片段,从而关闭连接:
if(doc == null) {
console.dir("Closing database connection");
return db.close();
}
之后,由于没有可用的数据库连接,所有未完成处理的更新都将出错。
正确的处理方法是什么,以便只有在所有文档都成功更新后才能关闭连接?
正如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();
}
});
}
});
});
我通常认为节点流接口是迭代器的更好选择。光标对象上有一个.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();
});
事实上,从本机驱动程序的2.0版本开始,流接口就是默认游标对象的一部分。
但一般情况下,对于一次性处理脚本,只调用db.close()
。通常,在服务器类型的实现中根本不应该调用它,而应该在整个生命周期中保持连接打开。
- 错误:$injector:modulerr模块错误(我的第一个SPA应用程序)
- 动态代码中存在系统应用程序地址错误
- Rails第一个应用程序错误——Errno::ENOENT
- 为什么Highchart在我的rails应用程序中加载了两次?(未捕获的Highcharts错误#16)
- 尝试在expressJS应用程序中使用haml咖啡时出现奇怪错误
- 应用程序在“关闭”之后停止工作(控制台中没有错误);咕哝的构造”;
- 流星应用程序中的按钮位置错误
- Windows 8应用程序正在运行,现在得到0x800a1391-JavaScript运行时错误:'WinJS&
- React应用程序错误'未捕获的ReferenceError:React未定义'
- 在遍历光标和更新文档时,连接因应用程序错误而关闭
- 非常奇怪的Parse.com应用程序错误100
- 工作灯Facebook应用程序错误:“给定的URL是不允许的应用程序配置”
- Facebook登录本地应用程序错误
- 应用程序错误是一个目录(文件:///#android_asset/www/index.html)
- Phonegap - JNI错误(应用程序错误):本地引用表溢出(max=512)
- Facebook应用程序错误显示一个用户而不是其他用户
- 节点js出现Heroko应用程序错误
- 使用本地存储功能的Phonegap应用程序错误
- Cloud9 上最简单的 nodejs 应用程序错误
- 谷歌日历导出应用程序错误