在脚本中关闭Mongoose连接,该连接不会永远运行

时间:2014-05-30 08:19:27

标签: javascript node.js mongoose

我有一个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&猫鼬迫使你陷入了可怕的境地。

1 个答案:

答案 0 :(得分:0)

您可以使用async库管理控制流程。通过使用其中一种控制流方法,您可以在完成所有保存后调用Mongoose上的断开连接。

您可以做的是将所有保存操作存储在数组中,然后将其传递给async.seriesasync.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();
});
相关问题