Saturday 6 May 2017

Execute a function after a tree walk has completed with callbacks

I have a simple tree with ids that are keys to a Mongo collection. I'm using a node library called treewalker. As I walk each node of the tree, I'm trying to look up the name (using mongoose) and simply append it to the current node. If I don't do a callback to lookup the node name, and just use some fixed value, I get the value I'm expecting. Let me illustrate in code:

Here is my tree:

{
  "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": []
        }
      ]
    }
  ]
}

Here is code that does what I want:

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));

However, as soon as I throw in a mongoose callback to get the category name, the category tree that's printed no longer has the names.

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));

I know this is an issue of timing, but I can't figure out how to solve it. I've seen several SO Articles like this one that suggest tracking callbacks and continuing only after they've all been called. I can't figure out how to apply that pattern to my case because I'm walking a tree and not just iterating a flat list. I'm starting to think that my problem might that I'm using the treewalker library, vs. just writing my own algorithm with callbacks after each node is visited.

I really appreciate your help!



via tobyb

No comments:

Post a Comment