如何在 Mongoose 中管理批量保存?我看到它可能还不可能:
有人提到使用一些流控制库,例如q
,但我也注意到猫鼬中有承诺,可以使用吗?我可以在 jQuery Deferred/Promises 中做喜欢的事吗
$.when(obj1.save(), obj2.save(), obj3.save()).then ->
# do something?
是的,你可以通过 Promise 做到这一点。如果您使用的是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(其作用类似于结果的占位符)。然后我们等待 promise 数组中的所有 promise 完成。
大多数好的Promises/A+兼容库都有一些等价于Q.all
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();
});
节点 --version v4.1.1
猫鼬@4.1.8
由于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...
})
要并行保存多个 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();
}
});
});
一个关于如何使用异步并行的精炼示例是:
async.parallel([obj1.save, obj2.save, obj3.save], callback);
由于 Mongoose 中的约定与 async (err, callback) 中的约定相同,因此您无需将它们包装在您自己的回调中,只需将您的保存调用添加到一个数组中,当一切完成时您将收到一个回调。
怎么样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();
}
@ForbesLindesay 当您可以使用承诺的猫鼬实现并创建自己的 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;
然后将它与猫鼬一起使用:
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);
});