Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a JSON tree in Node.Js from MongoDB

I am trying for a couple of days to create a JSON tree from my MongoDB. I use the child reference model structure, where "Books" is the root node.
I am trying to achieve a JSON tree of this form:

[{
    title: "Books",
    children: [{
        title: "Programming",
        children: [{
            title: "Databases",
            children: [{
                title: "MongoDb"
            }, {
                title: "Postgres"
            }]
        }, {
            title: "Languages"
        }]
    }, {
        title: "Item 2"
    }, {
        title: "Item 3"
    }, {
        title: "Item 4"
    }]
}]

But I am really struggling to make it works. The first level (Books, Item 2/3/4) can only have 5 items, but other submenus can have an infinity.

How can I achieve the transformation form the array of data that the call to Mongo will give to this tree structure ? Thanks in advance

like image 847
Simon Avatar asked Jun 25 '26 00:06

Simon


1 Answers

Lets say that you have to following data (already loaded from db):

var data = [
  { _id: "MongoDB", children: [] },
  { _id: "Postgres", children: [] },
  { _id: "Databases", children: [ "MongoDB", "Postgres" ] },
  { _id: "Languages", children: [] },
  { _id: "Programming", children: [ "Databases", "Languages" ] },
  { _id: "Books", children: [ "Programming" ] }
];

Since _id is unique, then in first step you convert it to dictionary, where keys are ids:

var dct = {};
for (var i = 0; i < data.length; i++) {
    var doc = data[i];
    dct[doc._id] = doc;
}

Now you loop through data array one more time and set children:

for (var i = 0; i < data.length; i++) {
    var doc = data[i];
    var children = doc.children;
    var ref_children = [];
    for (var j = 0; j < children.length; j++) {
        var child = dct[children[j]]; // <-- here's where you need the dictionary
        ref_children.push(child);
    }
    doc.children = ref_children;
}

And voila, you're done:

JSON.stringify(data);

EDIT

If you want only roots (nodes which are not children of any other node), then first you have to find them:

var get_parent = function(node, docs) {
    for (var i = 0; i < docs.length; i++) {
        var doc = docs[i];
        if (doc.children.indexOf(node) != -1) {
            return doc;
        }
    }
    return null;
};

var roots = [];
for (var i = 0; i < docs.length; i++) {
    var doc = data[i];
    if (get_parent(doc, docs) === null) {
        roots.push(doc);
    }
}
JSON.stringify(roots);

More efficient way would be to store parents when dereferencing children (compare with the code above EDIT):

for (var i = 0; i < data.length; i++) {
    var doc = data[i];
    var children = doc.children;
    var ref_children = [];
    for (var j = 0; j < children.length; j++) {
        var child = dct[children[j]]; // <-- here's where you need the dictionary
        child.has_parent = true; // <-- has a parent
        ref_children.push(child);
    }
    doc.children = ref_children;
}

var roots = [];
for (var i = 0; i < data.length; i++) {
    var doc = data[i];
    if (!doc.has_parent) {
        roots.push(doc);
    }
}
JSON.stringify(roots);
like image 156
freakish Avatar answered Jun 26 '26 12:06

freakish



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!