关闭一个不会永远运行的脚本中的Mongoose连接
Closing a Mongoose connection in a script which does not run forever
我有一个JavaScript程序,应该运行一段时间,插入行到MongoDB数据库,然后退出。以下是该应用程序的精简版本:
var mongoose = require('mongoose');
var models = require('./models');
mongoose.connect('mongodb://localhost/test')
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback() {
var row = models('testschema')({
name : 'test'
});
row.save(function (err, obj) {
if (err) {
console.log(err);
} else {
console.log('Saved item.');
}
});
console.log('Closing DB');
db.close();
});
现在上面的代码不能正常工作了,因为项目永远不会进入数据库。我的感觉是,因为save()是异步的,db.close()首先发生,项目永远不会被保存。如果我将db.close()调用移动到保存的回调中,如下所示:
row.save(function (err, obj) {
if (err) {
console.log(err);
} else {
console.log('Saved meeting details');
}
console.log('Closing DB');
db.close();
});
那么它工作得很好。然而,这并没有多少实际帮助,因为这意味着我只能在需要关闭数据库之前写入一行。我的问题是,当我在这种情况下如何正确关闭Mongoose连接:
var mongoose = require('mongoose');
var models = require('./models');
mongoose.connect('mongodb://localhost/test')
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback() {
itemsToSave.forEach(function(item) {
var row = models('testschema')({
name : item.name
});
row.save(function (err, obj) {
if (err) {
console.log(err);
} else {
console.log('Saved meeting details');
}
// Can't do this here.
//console.log('Closing DB');
//db.close();
});
});
// Nor here.
//console.log('Closing DB');
//db.close();
});
编辑:下面是使用C Blanchard答案的最终版本。我应该注意到,虽然它确实达到了预期的结果,但我觉得它在这一点上已经失去了猫鼬的便利性。如果您要像这样批量调用save(),您不妨利用MongoDB的底层批量插入功能,并使用它来执行插入。我可能会在另一种语言中完成这项任务,因为node.js的异步性质似乎使得几乎不可能编写优雅的代码来做诸如"打开文本文件,将每一行插入数据库,关闭连接并退出"之类的事情。总之,不多说了,最后一个程序:
var mongoose = require('mongoose');
var models = require('./models');
var async = require("async");
var rowsToSave = [];
var saveRow = function(item) {
return function (callback) {
console.log('Saving meeting details');
item.save(callback);
};
}
mongoose.connect('mongodb://localhost/test')
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function callback() {
rowsToSave.push(saveRow(models('testschema')({ name: 'name1' })));
rowsToSave.push(saveRow(models('testschema')({ name: 'name2' })));
rowsToSave.push(saveRow(models('testschema')({ name: 'name3' })));
rowsToSave.push(saveRow(models('testschema')({ name: 'name4' })));
console.log(JSON.stringify(rowsToSave));
async.series(rowsToSave, function (err, res) {
if (err) {
console.log(err);
} else {
console.log('Saved meeting details');
}
console.log('Closing DB');
db.close();
});
});
另一种方法,在查看代码时在某些方面更好,但也是一种非常糟糕的绕过此缺陷的方法,是简单地猜测脚本所需的时间,然后在此时间过去后关闭db:
setTimeout(function() { db.close(); }, 5000);
我不会责怪任何人这样做,MongoDB & &;猫鼬把你逼到了一个可怕的境地。
可以使用async库来管理控制流。通过使用其中一种控制流方法,您可以在完成所有保存后在Mongoose上调用disconnect。
你可以做的是将所有保存操作存储在一个数组中,然后将其传递给async.series
。async.series
有两个参数。1)一系列要调用的函数。2)当参数1中的所有函数被调用时调用的函数。
下面是遵循上述方法的解决方案的草图:
// Bring in async library
var async = require("async");
// Create an array to store your save operations
var rowsToSave = [];
// Returns a function that will save a row when invoked
var saveRowMethod = function (item) {
var row = models('testschema')({
name : item.name
});
return function (callback) {
row.save(callback);
};
}
db.once('open', function callback() {
itemsToSave.forEach(function(item) {
// Store the row to save
rowsToSave.push(saveRowMethod(item))
});
// This will invoke each save operation in rowsToSave (in series)
async.series(rowsToSave, function (error, result) {
if (error) {
// Handle an error if one of the rows fails to save
}
console.log('Closing DB');
db.close();
})
});
注意,传递给rowsToSave
的函数必须在保存完成时接受并调用回调。这就是async如何能够跟踪操作何时完成。
更新:看了你的评论,我又想了一下。找到了一个更简洁的解决方案,它只依赖于Model#create
-但是Mongoose现在不支持批量插入(Issue #723)
Model#create
接受一个对象数组,它将做一些类似于我上面概述的解决方案,除了它不需要async。
var rowsToSave = [];
rowsToSave.push({ name: 'name1' });
rowsToSave.push({ name: 'name2' });
rowsToSave.push({ name: 'name3' });
rowsToSave.push({ name: 'name4' });
TestModel.create(rowsToSave, function (err, name1, name2, name3, name4) {
if (err) {
console.log(err);
} else {
console.log('Saved meeting details');
}
console.log('Closing DB');
db.close();
});
- 如何使用phaser使html5游戏在移动设备浏览器上运行
- 使用压缩的JavaScript文件(不是运行时压缩)
- While循环在JavaScript中永远运行
- 动态弹出窗口'通过调用一个永远运行并返回's每个周期后的数据
- 如何在不停止的情况下永远运行node-js
- “流星运行安卓设备”需要永远安装Cordova插件
- 运行节点.js永远的脚本
- Javascript-Can'我不能让我的程序运行——循环永远不会结束
- 永远运行sail.js+angularjs项目得到未知提供者:a
- 如何永远运行流星?使用第三方数据库效果好吗
- 如何创建一个RxJS缓冲区,将NodeJS中的元素分组,但不依赖于永远运行的间隔
- Jquery上的Promise回调在空响应时永远不会运行
- jQuery ready函数不工作,它永远不会运行
- Node.js永远停止在同一机器上运行的其他服务
- 关闭一个不会永远运行的脚本中的Mongoose连接
- 使用超测运行Mocha测试时,Express路由永远不会执行
- 永远运行一个Node.js Angular.js Gulp.js应用
- 如何确保php脚本永远不会运行两次
- Javascript程序在所有浏览器中永远运行
- offlineAudioContext.在iOS上运行startRendering()后,oncomplete永远不会触