jenryb
jenryb

Reputation: 2117

How to traverse nested data

I have to traverse a large data set to collect the final child element of the nodes in javascript.

I need to end up with an array of the Branch Codes found in the child Details. Here is the output I'm attempting to get:

[1000, 1201, 1202, 2101, 3101, 3201]

{
  "TITLE": {
    "FirstLevel": {
      "Details": {
        "Code": "01",
      },
      "SecondLevel": [
        {
          "Details": {             
            "Description": "{desc}",          
          },
          "ThirdLevel": {
            "Details": {
              "Code": "01",
            },
            "FourthLevel": [
              {
                "Details": {
                  "Code": "11",
                },
                "Branch": {
                  "Details": {
                    "Code": "1000",
                  }
                }
              },
              {
                "Details": {
                  "Code": "12",
                },
                "Branch": [
                  {
                    "Details": {
                      "Code": "1201",
                    }
                  },
                  {
                    "Details": {
                      "Code": "1202",
                    }
                  }
                ]
              }
            ]
          }
        },
        {
          "Details": {
            "Code": "100",
          },
          "ThirdLevel": [
            {
              "Details": {
                "Code": "02",
              },
              "FourthLevel": {
                "Details": {
                  "Code": "21"
                },
                "Branch": {
                  "Details": {
                    "Code": "2101",
                  }
                }
              }
            },
            {
              "Details": {
                "Code": "03",
              },
              "FourthLevel": [
                {
                  "Details": {
                    "Code": "31",
                  },
                  "Branch": {
                    "Details": {
                      "Code": "3101",
                    }
                  }
                },
                {
                  "Details": {
                    "Code": "32",
                  },
                  "Branch": {
                    "Details": {
                      "Code": "3201",
                    }
                  }
                }
              ]
            }
          ]
        }
      ]
    }
  }
}

I've looked at answers on more basic questions and tried to adapt the solution.

One such solution takes in an id passed, and will update the name based on the id. I thought I could use the similar map implementation here. There is an issue because the array doesn't just have 'children' to represent where there will be child nodes.

function update(object, passedId) {

    object.children.map((element, index) => {
        if (element.id === passedId) {
            console.log(index)
            object.children[index].name = "New Name"
        }
        if (element.children != null) { // condition for checking Nesting
            update(element, passedId)
        }
    })

    console.log(object.children)
}

update(obj, "Branch");

Next I tried a more simple approach

function getSubItem(obj) {
  for (item in obj) {
    for (subItem in obj[item]) {
      for (subsubItem in obj[subItem]){
      console.log(obj[item][subItem][subsubItem]);
      }
    }
  }
}
getSubItem(obj)

and so on, adding sub after sub after sub item, but that kind of nested for looping seems incredibly unstable, and since branches can be nested in different areas it doesn't seem reliable either. Am I missing an easy solution here?

Upvotes: 1

Views: 197

Answers (3)

Yuri Gor
Yuri Gor

Reputation: 1463

Try _.eachDeep method from Deepdash (deep Lodash extension).

Here is your case: https://codepen.io/yurigor/pen/moMpLV

var res = [];
_.eachDeep(data,function(value,key){
  if(key=="Branch"){
    if(!_.isArray(value)){
      value = [value];
    }
    _.each(value,function(v){
      if(v.Details&&v.Details.Code){
        res.push(v.Details.Code);
      }
    });
  }
});

Upvotes: 0

xianshenglu
xianshenglu

Reputation: 5329

try this:

const obj = {
    "TITLE": {
        "FirstLevel": {
            "Details": {
                "Code": "01",
            },
            "SecondLevel": [{
                    "Details": {
                        "Description": "{desc}",
                    },
                    "ThirdLevel": {
                        "Details": {
                            "Code": "01",
                        },
                        "FourthLevel": [{
                                "Details": {
                                    "Code": "11",
                                },
                                "Branch": {
                                    "Details": {
                                        "Code": "1000",
                                    }
                                }
                            },
                            {
                                "Details": {
                                    "Code": "12",
                                },
                                "Branch": [{
                                        "Details": {
                                            "Code": "1201",
                                        }
                                    },
                                    {
                                        "Details": {
                                            "Code": "1202",
                                        }
                                    }
                                ]
                            }
                        ]
                    }
                },
                {
                    "Details": {
                        "Code": "100",
                    },
                    "ThirdLevel": [{
                            "Details": {
                                "Code": "02",
                            },
                            "FourthLevel": {
                                "Details": {
                                    "Code": "21"
                                },
                                "Branch": {
                                    "Details": {
                                        "Code": "2101",
                                    }
                                }
                            }
                        },
                        {
                            "Details": {
                                "Code": "03",
                            },
                            "FourthLevel": [{
                                    "Details": {
                                        "Code": "31",
                                    },
                                    "Branch": {
                                        "Details": {
                                            "Code": "3101",
                                        }
                                    }
                                },
                                {
                                    "Details": {
                                        "Code": "32",
                                    },
                                    "Branch": {
                                        "Details": {
                                            "Code": "3201",
                                        }
                                    }
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    }
};

function transData(data, propertyName, path, result = []) {
	
    if (data instanceof Array) {
        data.forEach(obj => transData(obj, propertyName, path, result));
    } else if (data instanceof Object) {
        let existProperty = Object.keys(data).indexOf(propertyName) > -1;
        if (existProperty) {
            getCode(data[propertyName], path, result);
        } else {
            Object.keys(data).forEach(key => transData(data[key], propertyName, path, result));
        }
    }

    function getCode(data, path, result) {
        if (data instanceof Array) {
            data.forEach(obj => getCode(obj, path, result));
        } else {
            if (typeof path !== 'undefined') {
                result.push(path.split(/\./g).reduce((accumulator, val) => accumulator = accumulator[val], data));
            } else {
                result.push(data);
            }
        }
    }

    return result;
}

console.log(transData(obj, 'Branch', 'Details.Code'));
console.log(transData(obj, 'Branch'));

Upvotes: 1

stasovlas
stasovlas

Reputation: 7416

something like:

function update (data, passedId, acc = []) {
    if (!_.isObject(data)) {
        return acc;
    }

    return _.reduce(_.values(data), (result, item) => {
        result = _.chain(item)
            .get(passedId)
            .thru(val => [val])
            .flatten()
            .compact()
            .map('Details.Code')
            .thru(vals => _.concat(result, vals))
            .value();
       return update(item, passedId, result);
    }, acc);
}

const res = update(data, 'Branch');

Upvotes: 1

Related Questions