Reputation: 2117
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
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
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
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