2017-05-06 12 views
1

私はMongoコレクションのキーであるIDを持つ単純なツリーを持っています。私はtreewalkerというノードライブラリを使用しています。私はツリーの各ノードを歩いているので、(マングースを使用して)名前を調べて、現在のノードに単純に追加しようとしています。ノード名を参照するためのコールバックを行わず、単に固定値を使用すると、私は期待している値を取得します。私はコードで説明してみましょう。ここではコールバックでツリーウォークが完了した後に関数を実行

は私の木である:

{ 
    "categoryTree": [ 
    { 
     "categoryId": "1", 
     "children": [ 
     { 
      "categoryId": "2", 
      "children": [ 
      { 
       "categoryId": "3", 
       "children": [] 
      }, 
      { 
       "categoryId": "4", 
       "children": [] 
      } 
      ] 
     }, 
     { 
      "categoryId": "5", 
      "children": [] 
     }, 
     { 
      "categoryId": "6", 
      "children": [] 
     } 
     ] 
    }, 
    { 
     "categoryId": "7", 
     "children": [ 
     { 
      "categoryId": "8", 
      "children": [] 
     } 
     ] 
    } 
    ] 
} 

ここで私が何をしたいんコードです:

catTree.categoryTree.forEach(function(node){ 
    var counter = 0; 
    tree.walkTree(node, 'children', function(obj){ 
     obj.name = counter++; 
    }); 
}); 
//This tree has the names (as the counter above) in it as I expect 
console.log(JSON.stringify(catTree)); 

は、すぐに私はマングースのコールバックで投げるように、しかし、カテゴリ名を取得すると、印刷されたカテゴリツリーには名前がなくなります。

catTree.categoryTree.forEach(function(node){ 
    tree.walkTree(node, 'children', function(obj){ 
     //Cat is a mongoose model defined elsewhere 
     Cat.findById(obj.categoryId, {_id:0,name:1}).exec(function(err, value){ 
      obj.name = value.name; 
     }); 
    }); 
}); 
//This tree has NO names :(
console.log(JSON.stringify(catTree)); 

私はこれがタイミングの問題であることを知っていますが、解決方法を理解できません。私はコールバックを追跡し、すべてが呼び出された後にのみ続けることを提案するいくつかのSOの記事like this oneを見ました。私はツリーを歩いているだけでフラットなリストを繰り返しているわけではないので、そのパターンを私のケースに適用する方法を理解できません。私は自分の問題は私がtreewalkerライブラリを使用していると思うかもしれないと思っています。各ノードが訪問した後でコールバックを使って独自のアルゴリズムを書くだけです。

本当にありがとうございます。

+0

look at async.js – Alex

答えて

2

データベース呼び出しは非同期です。これは、彼らが、ある程度の時間を完了することを意味します。これは、.forEach()の繰り返しが終わってからです。データベースが一度に(並行して、基本的にすべてのそれらのクエリを実行している)、それにスローされるクエリのツリー全体を処理できる場合は、このような単純な何かを行うことができます:

let cntr = 0; 
catTree.categoryTree.forEach(function(node){ 
    tree.walkTree(node, 'children', function(obj){ 
     //Cat is a mongoose model defined elsewhere 
     ++cntr; 
     Cat.findById(obj.categoryId, {_id:0,name:1}).exec(function(err, value){ 
      --cntr; 
      if (!err) { 
       obj.name = value.name; 
      } 
      // see if all requests are done 
      if (cntr === 0) { 
       console.log(JSON.stringify(catTree)); 
      } 
     }); 
    }); 
}); 

いつでもあなたはコーディネートしようとしています複数の非同期オペレーションを使用する場合、通常は約束を使用することが理にかなっています(これは、それが正確に構築されたものなので)。そして、mongooseは、クエリに対して約束を組み込んでいます。ここでは、各クエリの約束事を配列に集めてから、Promise.all()がすべて完了したときにそれを伝えます。

let promises = []; 
catTree.categoryTree.forEach(function(node){ 
    tree.walkTree(node, 'children', function(obj){ 
     //Cat is a mongoose model defined elsewhere 
     let p = Cat.findById(obj.categoryId, {_id:0,name:1}).exec().then(function(value) { 
      obj.name = value.name; 
     }); 
     promises.push(p); 
    }); 
}); 

Promise.all(promises).then(function() { 
    console.log(JSON.stringify(catTree)); 
}).catch(function(err) { 
    // error 
    console.log(err); 
}); 
+0

これはすばらしいです!答えと約束の説明に感謝します。もし私があなたにビールを買うことができたら、私はそうするでしょう。 – tobyb

関連する問題