我有一个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()调用移动到save的回调中,如下所示:
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的异步性质似乎几乎不可能编写优雅的代码来执行诸如"打开文本文件之类的内容,每行将其插入数据库,关闭连接和退出"。无论如何,没有进一步的adieu,最终的计划:
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();
});
});
另一种方法,在某些方面在查看代码时更好,但也是一个可怕的可怕的黑客来解决这个缺陷,是简单地猜测脚本所需的时间,然后在此之后关闭数据库已经过去了:
setTimeout(function() { db.close(); }, 5000);
我不会责怪任何人这样做,MongoDB&猫鼬迫使你陷入了可怕的境地。
答案 0 :(得分:0)
您可以使用async库管理控制流程。通过使用其中一种控制流方法,您可以在完成所有保存后调用Mongoose上的断开连接。
您可以做的是将所有保存操作存储在数组中,然后将其传递给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
的函数必须在保存完成时接受并调用回调。这就是异步能够跟踪操作何时完成的过程。
更新:在您发表评论后我更加深思熟虑。找到一个只依赖于Model#create
的整洁解决方案 - 但是Mongoose目前不支持批量插入(Issue #723)
Model#create
接受一个对象数组,并且会执行类似于上面概述的解决方案,除非它不需要异步。
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();
});