Generate JSON tree from mongoDB data in node.js

There are lot of questions like this, but unfortunately I dont find any of them fitting my case.

Closest is Create a JSON tree in Node.Js from MongoDB but it still doesnt work as expected.

Or maybe my head cant wrap this problem...

I have schema that key components for my problem looks like this:

var userSchema = new Schema({
    _id:            {type: Number},
    children:   [{type: Number, ref: 'User'}]
)};

each user may have three children users, so it can go infinately deep.

Fortunately, i have to cover two scenarios -

  1. build json tree from specific user up to 3 nestings
  2. calculate data for 10 nestings from specific root.

I tried to write recursive function like this in my express.js api:

api.get('/user/tree/:user_id', function (req, res) {

    var user_id = req.params.user_id;
    var depth = 0;
    var root = {};

    function walker(parent) {
        if (depth >= 3) {
            return res.send('whole data, not just last user'); // this is wrong. it will try to res.send for each iteration of forEach, and it sends only last user.
        }
        depth += 1;
        _.forEach(parent.mlm.childs, function (userid, index) {
            User.findOneAsync({_id: userid}).then(function(user) {
                parent.mlm.childs[index] = user;
                walker(parent.mlm.childs[index]);
            });
        });
    }

    User.findOneAsync({_id: user_id}).then(function(user) {
        root = user;
        walker(user, root);
    });
});

but of course it only traverse the tree, instead of traverse and create whole JSON.

Im stuck on how to be able to access the root and send whole tree.

problem of sending many res.send can be solved by counting iterations and send only if forEach ended, i guess.

Thanks for any help.

Ok. I found a solution.

api.get('/user/tree/:user_id', function (req, res) {

    var user_id = req.params.user_id;
    var tree = {};
    var counter = 0;
    var gloCounter = 0;

    function walker(parent) {
        gloCounter += 1;
        if (parent.mlm.childs.length === 0  && gloCounter > counter) {
            res.send(tree);
            return;
        }

        _.forEach(parent.mlm.childs, function (child, i) {
            counter += 1;
            User.findOneAsync({_id: child})
                .then(function(child) {
                    parent.mlm.childs[i] = child;
                    var newParent = parent.mlm.childs[i];
                    walker(newParent);
                }).catch(function(err) {
                    console.log('error: ' + err);
                });

        });
    }

    User.findOneAsync({_id: user_id})
        .then(function(user) {
                tree = user;
                walker(tree);

        }).catch(function(err) {
            console.log('err: ' + err);
        });
});

It works as expected - traverse through whole structure, and create json, that is sent back. It uses lodash and bluebird promises, for those who would solve similar problem in future and dont understand what is happening with all those "Async" sufixes and _.forEach.