我有以下代码,我遍历一个集合并执行另一个db查询并在其回调中构造一个对象。最后,我将该对象保存到另一个集合中。
我想在保存所有项目后调用另一个函数,但无法弄清楚如何。我尝试使用异步库,特别是异步,而当item不为null时,这只会让我陷入无限循环。
有没有办法确定所有项目何时保存?
谢谢!
var cursor = db.collection('user_apps').find({}, {timeout:false});
cursor.each(function (err, item) {
if (err) {
throw err;
}
if (item) {
var appList = item.appList;
var uuid= item.uuid;
db.collection('app_categories').find({schema_name:{$in: appList}}).toArray(function (err, result) {
if (err) throw err;
var catCount = _.countBy(result, function (obj) {
return obj.category;
})
catObj['_id'] = uuid;
catObj['total_app_num'] = result.length;
catObj['app_breakdown'] = catCount;
db.collection('audiences').insert(catObj, function (err) {
if (err) console.log(err);
});
});
}
else {
// do something here after all items have been saved
}
});
答案 0 :(得分:2)
这里的关键是在执行“循环”操作时使用一些会尊重回调信号的东西。这里实现的.each()
不会那样做,所以你需要一个“异步”循环控件来表示每个循环已经迭代完成,并且它在回调中有自己的回调。
如果你的底层MongoDB驱动程序至少是版本2,那么有一个.forEach()
,它有一个回调,当循环完成时会调用它。这比.each()
更好,但它无法解决内部“异步”.insert()
操作何时完成的问题。
因此,更好的方法是使用.find()
返回的stream interface,其中允许更多流量控制。有一个.stream()
方法可以向后兼容,但现代驱动程序默认只返回接口:
var stream = db.collection('user_apps').find({});
stream.on("err",function(err){
throw(err);
});
stream.on("data",function(item) {
stream.pause(); // pause processing of stream
var appList = item.appList;
var uuid= item.uuid;
db.collection('app_categories').find({schema_name:{ "$in": appList}}).toArray(function (err, result) {
if (err) throw err;
var catCount = _.countBy(result, function (obj) {
return obj.category;
})
var catObj = {}; // always re-init
catObj['_id'] = uuid;
catObj['total_app_num'] = result.length;
catObj['app_breakdown'] = catCount;
db.collection('audiences').insert(catObj, function (err) {
if (err) console.log(err);
stream.resume(); // resume stream processing
});
});
});
stream.on("end",function(){
// stream complete and processing done
});
流上的.pause()
方法会停止发出更多事件,以便每次处理一个对象结果。当调用来自.insert()
的回调时,将调用.resume()
方法,表示该项目的处理已完成,并且可以进行新的调用以处理下一个项目。
当流完成后,一切都完成,所以调用“end”事件挂钩继续你的代码。
这样,每个循环都用一个结尾表示移动到下一个迭代,并且有一个定义的“结束”事件用于完整的处理结束。由于控件在.insert()
回调的“内部”,因此这些操作也可以完成。
作为旁注,您可以考虑在源集合中包含您的“类别”信息,因为如果所有必需数据都在一个集合中,您可能会使用.aggregate()
更有效地返回结果。< / p>