So there is array of objects of below format
let inputs = [
{
"id": "614344d9d9c21c0001e6af2e",
"groupName": "Unassigned",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f2e",
"groupName": "P1",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f38",
"groupName": "K1",
"parentGroup": "C1"
},
{
"id": "614447da152f69c3c1d52f3e",
"groupName": "A2",
"parentGroup": "C2"
},
{
"id": "614447da152f69c3c1d52f40",
"groupName": "G1",
"parentGroup": "P2"
},
{
"id": "614447da152f69c3c1d52f46",
"groupName": "F1",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f30",
"groupName": "P2",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f36",
"groupName": "C2",
"parentGroup": "P1"
},
{
"id": "614447da152f69c3c1d52f3c",
"groupName": "A1",
"parentGroup": "C2"
},
{
"id": "614447da152f69c3c1d52f34",
"groupName": "C1",
"parentGroup": "P1"
},
{
"id": "614447da152f69c3c1d52f32",
"groupName": "P3",
"parentGroup": "null"
},
{
"id": "614447da152f69c3c1d52f3a",
"groupName": "K2",
"parentGroup": "C1"
},
{
"id": "614447da152f69c3c1d52f42",
"groupName": "GG1",
"parentGroup": "G1"
},
{
"id": "614447da152f69c3c1d52f44",
"groupName": "GGG1",
"parentGroup": "GG1"
}
]
i am trying to create a tree structure of format
{name:'p1',children:[{name:'c1':children:[]}]}
so i sorted all the elements of given array considering element with parentGroup as "null" to be at the top of the array.
let finalArr = [];
inputs.sort((a,b)=> (a.parentGroup === "null") ? -1 : 1);
And for each element of the inputs array, i was iterating below logic
inputs.forEach(ele => {
if(ele.parentGroup === "null"){
let child= {name:ele.groupName,children:[]};
finalArr.push(child);
}else{
finalArr.forEach(item => {
this.findNode(item,ele);
})
}
});
If the 'parentGroup' of element is "null", then create a leaf kind of obj and push the element to 'finalArr' array
Else, then iterate across all the elements of 'finalArr' over a recursion function
public findNode(ele, obj){
if(ele.children.length === 0){
if(ele.name === obj.parentGroup){
let child = {name:obj.groupName, children:[]};
ele.children.push(child);
}
}else{
let j = ele.children.length-1;
this.findNode(ele.children[j--],obj);
}
}
This recursion function will check the element has children or not, if no children, then compare the parentGroup of given obj, with name of element from 'FinalArr'.
if so ,push the current obj to the children of the element of finalArr.
else, that is, when children has more elements, the same recursion will be triggered until depth of the element is reached.
With this i tought i would make a tree structure with given inputs array, but when a parent has more children, of same level, this logic fails,
so the inputs array has 'c1' which is a child of 'p1', but nly the child 'c2' resides, not sure the what is that i missed.
You could take a standard algorithm for getting a tree with given data
const
getTree = (data, id, parent, root, fn = o => o) => {
var t = {};
data.forEach(o => ((t[o[parent]] ??= {}).children ??= []).push(Object.assign(t[o[id]] = t[o[id]] || {}, fn(o))));
return t[root].children;
},
data = [{ id: "614344d9d9c21c0001e6af2e", groupName: "Unassigned", parentGroup: "null" }, { id: "614447da152f69c3c1d52f2e", groupName: "P1", parentGroup: "null" }, { id: "614447da152f69c3c1d52f38", groupName: "K1", parentGroup: "C1" }, { id: "614447da152f69c3c1d52f3e", groupName: "A2", parentGroup: "C2" }, { id: "614447da152f69c3c1d52f40", groupName: "G1", parentGroup: "P2" }, { id: "614447da152f69c3c1d52f46", groupName: "F1", parentGroup: "null" }, { id: "614447da152f69c3c1d52f30", groupName: "P2", parentGroup: "null" }, { id: "614447da152f69c3c1d52f36", groupName: "C2", parentGroup: "P1" }, { id: "614447da152f69c3c1d52f3c", groupName: "A1", parentGroup: "C2" }, { id: "614447da152f69c3c1d52f34", groupName: "C1", parentGroup: "P1" }, { id: "614447da152f69c3c1d52f32", groupName: "P3", parentGroup: "null" }, { id: "614447da152f69c3c1d52f3a", groupName: "K2", parentGroup: "C1" }, { id: "614447da152f69c3c1d52f42", groupName: "GG1", parentGroup: "G1" }, { id: "614447da152f69c3c1d52f44", groupName: "GGG1", parentGroup: "GG1" }],
tree = getTree(data, 'groupName', 'parentGroup', null, ({ groupName: name }) => ({ name }));
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I think the issue is how finalArr is used to generate the html elements.
When doing console.log(finalArr) it looks like the code block below. So it seems to me like the code you have to build the structure of finalArr is working fine.
// console.log(finalArr)
[
{ "name": "P3", "children": [] },
{
"name": "P2",
"children": [
{
"name": "G1",
"children": [
{ "name": "GG1", "children": [
{ "name": "GGG1", "children": [] }
]
}
]
}
]
},
{ "name": "F1", "children": [] },
{
"name": "P1",
"children": [
{ "name": "C2", "children": [
{ "name": "A1", "children": [] }
]
}
]
},
{ "name": "Unassigned", "children": [] }
]
EDIT
As OP mentioned in the comment C1 was missing. I've introduced a root element that will have the finalArr as its children and changed the findNode to use a for loop instead of forEach. In this way we can also break when we find the node and not continue recursing.
As part of the initial sorting we will sort the inputs by parentGroup so we ensure that a childs parent is added in the tree structure before we try to find it with findNode.
I believe this produces the correct result:
inputs.sort((a, b) => (a.parentGroup === "null" ? -1 : 1));
// Sort by parentGroup
let root = inputs.pop();
let inputsDescending = [root];
let max = inputs.length * inputs.length;
let c = 0;
while (inputs.length > 0 && max > c) {
const child = inputs.pop();
const hasParentGroup = inputsDescending.find(
(parent) => parent.groupName === child.parentGroup
);
if (hasParentGroup || child.parentGroup === "null") {
inputsDescending.push(child);
} else {
inputs.unshift(child);
}
}
let rootEle = { name: "root", children: [] };
inputsDescending.forEach((obj) => {
if (obj.parentGroup === "null") {
let child = { name: obj.groupName, children: [] };
rootEle.children.push(child);
} else {
findNode(rootEle, obj);
}
});
function findNode(ele, obj) {
if (ele.name === obj.parentGroup) {
let child = { name: obj.groupName, children: [] };
ele.children.push(child);
return true;
} else {
const c = ele.children.length;
if (c > 0) {
for (let i = 0; c > i; i++) {
const found = findNode(ele.children[i], obj);
if (found) break;
}
}
}
}
const finalArr = rootEle.children;
Now finalArr looks like this:
[
{ "name": "Unassigned", "children": [] },
{
"name": "P1",
"children": [
{
"name": "C1",
"children": [
{ "name": "K1", "children": [] },
{ "name": "K2", "children": [] }
]
},
{
"name": "C2",
"children": [
{ "name": "A2", "children": [] },
{ "name": "A1", "children": [] }
]
}
]
},
{ "name": "F1", "children": [] },
{
"name": "P2",
"children": [
{ "name": "G1", "children": [
{ "name": "GG1", "children": [] }
]
}
]
},
{ "name": "P3", "children": [] }
]
Related
I currently have this array which repeats recursively:
[
{
"Name": "Test",
"Children": [
{
"Name": "Id",
"Property": "Placeholder",
"Children": [
{
"Name": "Child Id",
"Property": "Placeholder",
"Children": null
}
]
}
}
]
To get the structure I want I currently have this:
const fixed = data.map(item => item = {
data: {
name: item.Name,
},
children: item.Children.map(child => child = {
name: child.Name,
})
}
)
Is there a way to repeat my initial array.map recursively for each child array?
One possible solution, based on the output I believe you want:
const array = [{
"Name": "Test",
"Children": [{
"Name": "Id",
"Property": "Placeholder",
"Children": [{
"Name": "Child Id 1",
"Property": "Placeholder",
"Children": null
}, {
"Name": "Child Id 2",
"Property": "Placeholder",
"Children": [{
"Name": "Child Id 3",
"Property": "Placeholder",
"Children": null
}]
}]
}]
}];
const map = (arr) => {
return arr ? arr.map(fix) : null;
}
const fix = (item) => {
return {
data: {
name: item.Name
},
children: map(item.Children),
};
}
console.log(map(array))
Or as suggested below, use shortands:
const map = arr => arr ? arr.map(fix) : null;
const fix = item => ({
data: {
name: item.Name
},
children: map(item.Children),
});
We can use a base case where we check if the Children property is null,if so recursion stops and we return the Name:
const data = [{"Name": "Test", "Children": [{"Name": "Id","Property": "Placeholder","Children": [{"Name": "Child Id","Property": "Placeholder","Children": null }] }] }];
const flattenData = (data) => {
return data.map(d => {
//Base case, recursion stops here
if(!d.Children){
return d.Name;
}
//Continue recursion
return {data: {name: d.Name}, children: flattenData(d.Children) }
});
}
console.log(flattenData(data));
You can create a function that transforms children. If the child has other children, then the function will call itself to transform them recursively.
const input = [
{
"Name": "Test",
"Children": [
{
"Name": "Id",
"Property": "Placeholder",
"Children": [
{
"Name": "Child Id",
"Property": "Placeholder",
"Children": null
}
]
}
]
}
];
const transformChildren = children => children.map(child => ({
name: child.Name,
children: child.Children ? transformChildren(child.Children) : null
}));
const output = input.map(item => ({
data: {
name: item.Name,
},
children: item.Children ? transformChildren(item.Children) : null
}))
console.log(output)
I currently store a structure in a javascript Array with nested objects. The structure does not have a parentId parameter which I do need to get the parent of a nested object. The current structure outputs:
[{
"id":1000,
"pageIndex":0,
"type":"page",
"label":"Page 1",
"rows":[
{
"id":1002,
"type":"row 1",
"layout":{
"gutters":true,
"wrapping":false,
"guttersDirect":false,
"parentId":1002
},
"columns":[
{
"id":1003,
"type":"col 1",
"layout":{
"size":3,
"outOf":12,
"parentId":1003
}
},
{
"id":1004,
"type":"col 2",
"layout":{
"size":3,
"outOf":12,
"parentId":1004
},
"elements":[
{
"id":1006,
"type":"text",
"label":"Account ID"
}
]
},
{
"id":1005,
"type":"col 3",
"layout":{
"size":6,
"outOf":12,
"parentId":1005
}
}
]
}
]
}]
I need a function that updates all nested objects' parentId attribute with the parent nested object's id.
I have the following function
_PREV_PARENT_ID = null;
assignParentIds(object){
Object.keys(object).forEach(key => {
console.log(`key: ${key}, value: ${object[key]}`)
if(key === "id"){
this._PREV_PARENT_ID = object[key];
}else if (typeof object[key] === 'object') {
if(!!this._PREV_PARENT_ID){
object[key]['parentId'] = this._PREV_PARENT_ID;
}
this.assignParentIds(object[key])
}
});
}
However, this function fails to set parent ids correctly for items in array
[
{
"id":1000,
"pageIndex":0,
"type":"page",
"label":"Page 1",
"rows":[
{
"id":1002,
"parentId":1000,
"type":"row 1",
"layout":{
"gutters":true,
"wrapping":false,
"guttersDirect":false,
"parentId":1002
},
"columns":[
{
"id":1003,
"parentId":1002, <--- Correct
"type":"col 1",
"layout":{
"size":3,
"outOf":12,
"parentId":1003
}
},
{
"id":1004,
"parentId":1003, <--- In-Correct
"type":"col 2",
"layout":{
"size":3,
"outOf":12,
"parentId":1004
},
"elements":[
{
"id":1006,
"parentId":1004,
"type":"text",
"label":"Account ID"
}
]
},
{
"id":1005,
"parentId":1006, <--- In-Correct
"type":"col 3",
"layout":{
"size":6,
"outOf":12,
"parentId":1005
}
}
]
}
]
}
]
I thought about also potentially ditching parentId attribute and instead to use a function that would return the parent nested, however it also suffers from the same issue (if I call the function on id = 1004, it returns the previous item in the array with id = 1003 instead of returning the object with id 1002.
_PARENT_OBJECT = null;
findParentByChildId(o, id) {
if( o.id === id ){
return o;
}else{
if(o.hasOwnProperty('id')){
this._PARENT_OBJECT = o;
}
}
var result, p;
for (p in o) {
if( o.hasOwnProperty(p) && typeof o[p] === 'object' ) {
result = this.findParentByChildId(o[p], id);
if(result){
return this._PARENT_OBJECT;
}
}
}
return result;
}
Since the use case is about using drag and drop functionality, the parentId will often be updated and seems like an uneccesary extra attribute that we need to keep track of, it would be best if I had a way to call a function findParentByChildId().
What would be the best way to manage this?
I wanted to take a chance to figure it out. I've made a walker function which goes through every level and array and brings the id of the previous level with it. Then when it gets a match on an id it returns the parent id you are looking for. Or when it has no match it returns null.
const data = [{
"id": 1000,
"pageIndex": 0,
"type": "page",
"label": "Page 1",
"rows": [{
"id": 1002,
"type": "row 1",
"layout": {
"gutters": true,
"wrapping": false,
"guttersDirect": false,
"parentId": 1002
},
"columns": [{
"id": 1003,
"type": "col 1",
"layout": {
"size": 3,
"outOf": 12,
"parentId": 1003
}
},
{
"id": 1004,
"type": "col 2",
"layout": {
"size": 3,
"outOf": 12,
"parentId": 1004
},
"elements": [{
"id": 1006,
"type": "text",
"label": "Account ID"
}]
},
{
"id": 1005,
"type": "col 3",
"layout": {
"size": 6,
"outOf": 12,
"parentId": 1005
}
}
]
}]
}];
const walkTree = (entry, matchId, parentId = null) => {
let result = null;
for (const { id, ...rest } of entry) {
if (matchId === id) {
return parentId;
}
parentId = id;
for (const value of Object.values(rest)) {
if (Array.isArray(value)) {
result = walkTree(value, matchId, parentId);
break;
}
}
}
return result;
};
const findParentByChildId = id => walkTree(data, id);
// ID's to look up parents of.
const lookupParents = [
1000,
1002,
1003,
1004,
1005,
1006,
1007
];
// Log results.
for (const id of lookupParents) {
console.log(`Parent of ${id}:`, findParentByChildId(id));
}
{
"id": "1",
"name": "root",
"children": [
{
"id": "1.1",
"name": "Child 1",
"children": [
{
"id": "1.1.1",
"name": "Child 1-1",
"children": [
{
"id": "1-1-1",
"name": "Child 1-1-1",
"children": [
]
}
]
},
{
"id": "1.1.2",
"name": "Child 1-2",
"children": [
]
},
{
"id": "1.1.3",
"name": "Child 1-3",
"children": [
]
}
]
},
{
"id": "1.2",
"name": "Child 2",
"children": [
{
"id": "1.2.1",
"name": "Child 2-2",
"children": [
]
}
]
}
]
}
This is the JSON string as the response. Had to fetch for the parent elements recursively all the parents id.
For instance, input is 1.2.1 then it returns [1.2]
input is 1.1.3 then it returns [1.1, 1]
How can I achieve this?
Just a simple recursion using dfs
const data = JSON.parse('{"id":"1","name":"root","children":[{"id":"1.1","name":"Child 1","children":[{"id":"1.1.1","name":"Child 1-1","children":[{"id":"1-1-1","name":"Child 1-1-1","children":[]}]},{"id":"1.1.2","name":"Child 1-2","children":[]},{"id":"1.1.3","name":"Child 1-3","children":[]}]},{"id":"1.2","name":"Child 2","children":[{"id":"1.2.1","name":"Child 2-2","children":[]}]}]}')
function dfs (target, node) {
if (node.id === target) { return node.id }
if (!node.children) { return false } // we could even skip that line since in your data you seem to have an empty array
const has = node.children.find(c => dfs(target, c))
return has && [node.id].concat(has.id)
}
console.log(dfs('1.2.1', data))
console.log(dfs('1.1.3', data))
You could take an iterative and recursive approach and
chcek if the given data is not an object, then return
check for the id and if found return an empty array, which gets filled by the calling function
iterate children with a short circuit on found and call the function again.
function getParentIds(object, id) {
var ids;
if (!object || typeof object !== 'object') return; // no object
if (object.id === id) return []; // id found
return object.children.some(o => ids = getParentIds(o, id)) // call recursive function
? [...ids, object.id] // if found, take ids
: undefined; // otherwise return falsy
}
var data = { id: "1", name: "root", children: [{ id: "1.1", name: "Child 1", children: [{ id: "1.1.1", name: "Child 1-1", children: [{ id: "1-1-1", name: "Child 1-1-1", children: [] }] }, { id: "1.1.2", name: "Child 1-2", children: [] }, { id: "1.1.3", name: "Child 1-3", children: [] }] }, { id: "1.2", name: "Child 2", children: [{ id: "1.2.1", name: "Child 2-2", children: [] }] }] };
console.log(getParentIds(data, '1.2.1')); // ['1.2']
console.log(getParentIds(data, '1.1.3')); // ['1.1', '1']
console.log(getParentIds(data, 'foo')); // undefined
.as-console-wrapper { max-height: 100% !important; top: 0; }
You would have to parse the complete object to recursively inject the parent ids in child objects. Something like this will do the thing.
function injectParents(data, parents) {
if(!parents) {
parents = [];
}
parents.push(data.id);
data.children.map(child=>{
child.parents = parents;
if(child.children && child.children.length>0) {
child = injectParents(child, Array.from(parents));
}
return child;
});
return data;
}
Then you would normally call it like
const injectedResponse = injectParents(response, null);
you can use
for(let x in arrayName){
//here you can access the json
console.log(arayName(x).id)
}
Is this what are you looking for?
//Input
let input = '1.2.1';
//Data
data = JSON.parse('{"id":"1","name":"root","children":[{"id":"1.1","name":"Child 1","children":[{"id":"1.1.1","name":"Child 1-1","children":[{"id":"1-1-1","name":"Child 1-1-1","children":[]}]},{"id":"1.1.2","name":"Child 1-2","children":[]},{"id":"1.1.3","name":"Child 1-3","children":[]}]},{"id":"1.2","name":"Child 2","children":[{"id":"1.2.1","name":"Child 2-2","children":[]}]}]}')
//Main function start here
function findIdWhereChild(data, input) {
if (data.children?.find(x => x.id == input)) {
return data.id;
}
else {
if (data.children.length > 0) {
for (let i = 0; i < data.children.length; i++) {
let findalResult = findIdWhereChild(data.children[i], input);
if (findalResult) {
return findalResult;
};
};
} else {
return undefined;
}
}
};
//Execution LOGs
console.log(findIdWhereChild(data, input));
var obj = [
{
"name": "A1",
"children": [
{
"name": "A1-level1-child1",
"children": [
{
"name": "A1-level2-child1",
"children": [
{
"name": "A1-level3-child1",
"children": []
},
{
"name": "A1-level3-child2",
"children": []
}
]
}
]
},
{
"name": "A2-level1-child1",
"children": []
}
]
},
{
"name": "B1",
"children": [
]
}
];
From the above JSON object, if i check the value "A1-level3-child1", the function should give me its parent name as "A1-level2-child1". Same way, if i check for "A2-level1-child1",then it should be give me the parent value as "A1".
You could iterate the array or children and use a short circuit if the node is found.
function getParentName(array, name, parent = 'root') {
var result;
array.some(o => result = o.name === name && parent
|| o.children && getParentName(o.children, name, o.name));
return result;
}
var array = [{ name: "A1", children: [{ name: "A1-level1-child1", children: [{ name: "A1-level2-child1", children: [{ name: "A1-level3-child1", children: [] }, { name: "A1-level3-child2", children: [] }] }] }, { name: "A2-level1-child1", children: [] }] }, { name: "B1", children: [] }];
console.log(getParentName(array, "A1-level3-child1")); // A1-level2-child1
console.log(getParentName(array, "A2-level1-child1")); // A1
GoGo this code.
var parentMap = {}
function getParentMap(arr, parent) {
if (!(arr instanceof Array)) {
return;
}
for (o of arr) {
parentMap[o.name] = parent;
if (o.children && o.children.length) {
getParentMap(o.children, o);
//getParentMap(o.children, o.name);
}
}
}
var arr = [{
"name": "A1",
"children": [{
"name": "A1-level1-child1",
"children": [{
"name": "A1-level2-child1",
"children": [{
"name": "A1-level3-child1",
"children": []
},
{
"name": "A1-level3-child2",
"children": []
}
]
}]
},
{
"name": "A2-level1-child1",
"children": []
}
]
},
{
"name": "B1",
"children": []
}];
getParentMap(obj, null);
parentMap["A1-level3-child1"].name
If you can redefine this structure, you can add 'parent' on every node, so more easy to operate it.
I have a dummy data like this
i need to create a tree like this
CEO
A
A1
A2
My dummy look like this
let d = [
{
"name": "CEO",
"parent": null,
"id": "5847e80312896b2fa49ce428"
},
{
"name": "A",
"parent": "5847e80312896b2fa49ce428",
"id": "5847f58289046550aa05a49d"
},
{
"name": "A1",
"parent": "5847f58289046550aa05a49d",
"id": "584804b073697edd3d372529"
},
{
"name": "A2",
"parent": "5847e80312896b2fa49ce428",
"id": "584804b073697edd3d372539"
}
];
I have tried somthing like this
var newObj = {tree:d.filter(d=>!d.parent)};
var tree = newObj.tree;
for(let k in tree){
for(let i = 0 ; i < tree.length ; i++){
newObj.tree[i]['child']=this.returnChildNode(tree[i].id,d);
}
}
console.log(newObj);
private returnChildNode(parentId ,arr){
if(arr.filter(d=>d.parent===parentId).length < 1) return null ;
else return arr.filter(d=>d.parent===parentId);
}
Output getting is
{
"tree": [
{
"name": "CEO",
"parent": null,
"id": "5847e80312896b2fa49ce428",
"child": [
{
"name": "A",
"parent": "5847e80312896b2fa49ce428",
"id": "5847f58289046550aa05a49d"
},
{
"name": "A2",
"parent": "5847e80312896b2fa49ce428",
"id": "584804b073697edd3d372539"
}
]
}
]
}
How to complete it by recursion for deep going in generic way
Here's a recursive option using reduce
let d = [{
"name": "CEO",
"parent": null,
"id": "5847e80312896b2fa49ce428"
}, {
"name": "A",
"parent": "5847e80312896b2fa49ce428",
"id": "5847f58289046550aa05a49d"
}, {
"name": "A1",
"parent": "5847f58289046550aa05a49d",
"id": "584804b073697edd3d372529"
}, {
"name": "A2",
"parent": "5847e80312896b2fa49ce428",
"id": "584804b073697edd3d372539"
}]
const rec = (parent, arr) => {
const ref = parent ? parent.id : null
const children = arr.reduce((ac, x) => {
if (x.parent === ref)
ac.push(rec(x, arr))
return ac
}, [])
if (parent)
parent.children = children
return (
parent ?
parent :
children[0]
)
}
const res = rec(null, d)
console.log(res)
You can try this :
var data = [
{
name: "CEO",
parent: null,
id: "0"
},
{
name: "A",
parent: "0",
id: "1"
},
{
name: "A1",
parent: "1",
id: "2"
},
{
name: "A2",
parent: "1",
id: "3"
},
{
name: "A3",
parent: "1",
id: "4"
},
{
name: "b",
parent: "0",
id: "5"
},
{
name: "A1",
parent: "5",
id: "6"
},
{
name: "A2",
parent: "5",
id: "7"
},
{
name: "A3",
parent: "5",
id: "8"
},
];
// data is an array in the above format
function toTree(data) {
var childrenById = {}; // of the form id: [child-ids]
var nodes = {}; // of the form id: {name: children: }
var i, row;
// first pass: build child arrays and initial node array
for (i=0; i<data.length; i++) {
row = data[i];
nodes[row.id] = {name: row.name, children: []};
if (row.parent == null) {
// assume -1 is used to mark the root's "parent"
root = row.id;
} else if (childrenById[row.parent] === undefined) {
childrenById[row.parent] = [row.id];
} else {
childrenById[row.parent].push(row.id);
}
}
// second pass: build tree, using the awesome power of recursion!
function expand(id) {
if (childrenById[id] !== undefined) {
for (var i=0; i < childrenById[id].length; i ++) {
var childId = childrenById[id][i];
nodes[id].children.push(expand(childId));
}
}
return nodes[id];
}
return expand(root);
}
console.log(JSON.stringify(toTree(data)));