2017-09-28 113 views
2

我剛開始使用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); 
} 
+1

可能的重複[如何在for循環中使用貓鼬函數?](https://stackoverflow.com/questions/44569770/how-can-i-use-mongoose-functions-inside-a-for-循環) –

+0

@KevinB如果OP詢問如何將它與async.js一起使用,那麼它並不是真的重複。沒有提供的答案使用async.js。 – Mikey

回答

0

你有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); 
}) 

除了

貓鼬操作都是異步的,所以

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

不正確的,因爲你正在返回不是實際許諾文檔。

此外

可能能夠與virtual populationaggregation來簡化你的邏輯。

+0

非常感謝。有完善記錄的答案 – Michalis

+0

有沒有簡單的方法讓孩子們的孩子等等? – Michalis

+0

@Michalis我有這種感覺,你會問這個。不幸的是,我不知道也不認爲用async.js做一個好主意。你可能想重新考慮你的模式。 [This](https://docs.mongodb.com/v3.2/tutorial/model-tree-structures/)可能會有所幫助。 – Mikey