【问题标题】:Mongoose async call inside a loop with async library带有异步库的循环内的猫鼬异步调用
【发布时间】:2018-03-09 17:26:45
【问题描述】:

我刚开始使用 nodejs/mongoose,我想我遇到了一个典型的异步问题。有人可以指导我如何解决这个异步问题吗?

我有这个函数“getAreasRoot”,在里面我有一个循环来填充另一个异步函数的结果。如何使用异步库修复它?

areaSchema.statics.getAreasRoot = function(cb: any) {
    let self = this;
    return self.model("Area").find({ parentId: null }, function(err: any, docs: any){
        docs.forEach(function(doc: any){
            doc.name = "Hi " + doc.name;
            doc.children = self.model("Area").getAreasChildren(doc._id, function(err: any, docs: any){});
        })
        cb(err, docs);
    });
};

areaSchema.statics.getAreasChildren = function(id: any, cb: any) {
    return this.model("Area").find({ parentId: null }).exec(cb);
}

【问题讨论】:

标签: node.js mongodb mongoose mongoose-schema async.js


【解决方案1】:

您有 2 个任务:获取根,然后使用根获取子项。

如果我要使用 async.js 执行此操作,我会使用 async.waterfallasync.mapSeries 的组合。我们使用.waterfall 是因为我们想将第一个任务的结果传递给第二个任务。我们使用.mapSeries 是因为我们想要更改每个根区域的名称和子区域。

areaSchema.statics.getAreasRoot = function (cb) {
    let self = this;
    async.waterfall([
        // every task has a callback that must be fired at least/most once
        // to tell that the task has finished OR when an error has occurred
        function getRoots (cb1) {
            self.find({ parentId: null }, cb1);
        },
        function getChildren (roots, cb2) {
            async.mapSeries(roots, function (root, cb3) {
                // inside this block, we want to fire the innest callback cb3 when 
                // each iteration is done OR when an error occurs to stop .mapSeries
                self.find({ parentId: root._id }, function (err, children) {
                    // error: stop .mapSeries
                    if (err)
                        return cb3(err);
                    root.name = "Hi " + root.name;
                    root.children = children;
                    // done: send back the altered document
                    cb3(null, root);
                });
            // the last argument is fired when .mapSeries has finished its iterations
            // OR when an error has occurred; we simply pass the inner callback cb2
            }, cb2) 
        }
    // the last argument is fired when .waterfall has finished its tasks
    // OR when an error has occurred; we simply pass the original callback cb
    ], cb);
};

使用它

Area.getAreasRoot(function (err, areas) {
    console.log(err, areas);
})

一边

Mongoose 操作是异步的,所以

doc.children = self.model("Area").getAreasChildren(...) 

不正确,因为您返回的 Promise 与实际文档相反。

还有

可能可以使用virtual populationaggregation 来简化您的逻辑。

【讨论】:

  • 非常感谢。完美记录的答案
  • 有什么简单的方法可以同时获取孩子的孩子等等?
  • @Michalis 我感觉你会问这个。不幸的是,我不知道也不认为使用 async.js 是个好主意。您可能想重新考虑您的架构。 This 可能会有所帮助。
猜你喜欢
  • 2018-01-10
  • 2019-02-14
  • 2015-04-18
  • 2018-10-17
  • 2019-02-15
  • 1970-01-01
  • 2018-05-21
  • 2018-08-09
  • 2019-10-12
相关资源
最近更新 更多