Mongoose JS承诺?或者如何管理批量保存

时间:2012-08-11 08:03:11

标签: mongodb synchronization mongoose

如何在Mongoose中管理批量保存?我看到它可能还不可能:

Theres有些提到使用像q这样的流量控制库,但我也注意到mongoose中有promises,它可以用吗?我可以在jQuery Deferred / Promises中做到吗

$.when(obj1.save(), obj2.save(), obj3.save()).then ->
    # do something? 

8 个答案:

答案 0 :(得分:9)

是的,你可以用承诺来做到这一点。如果您使用的是Q promise库,则可以重新编写@ matz3的代码,如:

var tasks = [];

for (var i=0; i < docs.length; i++) {
  tasks.push(docs[i].save());
}

Q.all(tasks)
  .then(function(results) {
    console.log(results);
  }, function (err) {
    console.log(err);
  });

我们在循环中一次启动所有操作,但我们不等待它们中的任何一个完成,因此它们并行运行。我们向数组添加一个promise(对结果来说就像占位符一样)。然后我们等待承诺数组中的所有承诺完成。

大多数好的Promises/A+兼容库都有一些等同于Q.all

答案 1 :(得分:4)

mongoose现在允许您选择Promise实现。

这里我使用node.js默认系统Promise(ES6)烘焙到nodejs

var mongoose = require('mongoose');
    mongoose.Promise = global.Promise; // use system implementation

Promise.all(obj1.save(), obj2.save(), obj3.save())
.then(function(resultSaves) {

    console.log('parallel promise save result :');
    console.log(resultSaves);
    mongoose.disconnect();

}).catch(function(err) {

    console.log('ERROR on promise save :');
    console.log(err);
    mongoose.disconnect();
});

node --version V4.1.1

mongoose@4.1.8

答案 2 :(得分:3)

尝试parallel模块的async功能。

var functions = [];

for (var i=0; i < docs.length; i++) {
    functions.push((function(doc) {
        return function(callback) {
            doc.save(callback);
        };
    })(docs[i]));
}

async.parallel(functions, function(err, results) {
    console.log(err);
    console.log(results);
});

答案 3 :(得分:2)

要并行保存多个mongoose文档,您可以执行类似这样的简单操作(假设您有一个名为docs的文档要保存的数组:

var count = docs.length;
docs.forEach(function(doc) {
    doc.save(function(err, result) {
        if (--count === 0) {
            // All done; call containing function's callback
            return callback();
        }
    });
});

答案 4 :(得分:2)

由于mongoose现在支持承诺,您可以使用Promise.all().then(),因此它将在所有承诺得到解决时返回。

Promise.all([
  obj1.save(),
  obj2.save(),
  obj3.save()
])
.then(console.log)
.catch(console.error)

事实上,如果您始终使用save()方法,则可以在此处使用Array.map()

Promise.all([ obj1, obj2, obj3 ].map( obj => obj.save() )

Aaand也使用es6语法来解析生成的数组:

Promise.all([ obj1, obj2, obj3 ].map( obj => obj.save() )
.then( ([ savedObj1, savedObj2, savedObj3 ]) => {
   // do something with your saved objects...
})

答案 5 :(得分:1)

关于如何使用async parallel的精炼示例是:

  async.parallel([obj1.save, obj2.save, obj3.save], callback);

由于Mongoose中的约定与async(错误,回调)中的约定相同,因此您无需将它们包装在自己的回调中,只需在数组中添加保存调用即可在完成所有操作后获得回调

答案 6 :(得分:-1)

async.queue怎么样 一个简单的例子:

var queue = async.queue(function(obj, callback) {
  return obj.save(callback);
});

for (var i in objs) {
  var obj = objs[i];
  // Some changes on object obj
  queue.push(obj);
}

如果在清空队列后需要回调:

var emptyQueue = true;
var queue = async.queue(function(obj, callback) {
  return obj.save(callback);
});
queue.drain = function() {
  // Every callbacks are finished
  // bigCallback();
};

for (var i in objs) {
  var obj = objs[i];
  // Some changes on object obj
  queue.push(obj);
  emptyQueue = false;
}
if (emptyQueue) {
  // Call manually queue drain in case of the queue is empty
  //  and we need to call bigCallback() for example
  return queue.drain();
}

答案 7 :(得分:-1)

@ForbesLindesay为什么在使用mongoose实现promises并创建自己的All时加载外部库?

创建一个增强mongoose承诺的模块。

var Promise = require("mongoose").Promise;

Promise.all = function(promises) {
  var mainPromise = new Promise();
  if (promises.lenght == 0) {
    mainPromise.resolve(null, promises);
  }

  var pending = 0;
  promises.forEach(function(p, i) {
    pending++;
    p.then(function(val) {
      promises[i] = val;
      if (--pending === 0) {
        mainPromise.resolve(null, promises);
      }
    }, function(err) {
      mainPromise.reject(err);
    });
  });

  return mainPromise;
}

module.exports = Promise;

然后将它与mongoose一起使用:

require('./promise')

...

var tasks = [];

for (var i=0; i < docs.length; i++) {
  tasks.push(docs[i].save());
}

mongoose.Promise.all(tasks)
  .then(function(results) {
    console.log(results);
  }, function (err) {
    console.log(err);
  });