I take this has been asked before here filter nested tree object without losing structure
but what I am looking for is opposite of that.
For the JSON data
var items = [
{
name: "a1",
id: 1,
children: [{
name: "a2",
id: 2,
children: [{
name: "a3",
id: 3
}]
},
{
name: "b2",
id: 5,
children: [{
name: "a4",
id: 4
}]
}]
}
];
We want the filter so that if you search for a2
. It should return the following
var items = [
{
name: "a1",
id: 1,
children: [{
name: "a2",
id: 2,
children: [{
name: "a3",
id: 3
}]
}]
}
];
ie all the nodes in that tree path (from root to leaf node).
Any idea how to achieve in nodejs/javascript?
Thanks
Follow my example, you can change the code to suit your works:
var items = [ { name: "a1", id: 1, children: [{ name: "a2", id: 2, children: [{ name: "a3", id: 3 }] }, { name: "b2", id: 5, children: [{ name: "a4", id: 4 }] }] } ]; //console.log(items); //first, add depth (of each element) to array items var depths = items; //structure of path = [[0,length_1st],[1,length_2nd],[2,length_3rd],[3,length_4th],...,[last,length_last]] var path = []; //for first value of path path.push([0,depths.length]); //test to add depth for depths: depths.map(function add_depth(current){ current['depth'] = path[path.length-1][0]; if(current.children){ //continue to array children path.push([path[path.length-1][0]+1,current.children.length]); current.children.map(add_depth); }else{ //get back of path while(path.length>1 && path[path.length-1][1]<2){ path.pop(); } //decrease length path[...[x,length]] path[path.length-1][1]--; }; }); //console.log(depths); // has depth in array depths, now is function for search in array depths function search_name(str){ let path_result = []; let flagExit = false; depths.findIndex(function find_name(current,index){ if (flagExit){ return; }; if(current.name===str){ //finish at here path_result[current.depth] = index; flagExit = true; return; }else{ if(current.children){ path_result[current.depth] = index; current.children.findIndex(find_name); }; }; }); return path_result; }; var name_to_search = "a3"; var path_end = search_name(name_to_search); //console.log(path_end); //show result from path_end: var result = []; var self_items, self_result; if (path_end){ for(let i=0;i<path_end.length;i++){ if(i===0){ result[i] = {}; result[i]['name'] = items[path_end[i]].name; result[i]['id'] = items[path_end[i]].id; if(i === path_end.length-1){ //just the first result result[i]['children'] = items[path_end[i]].children; }else{ result[i]['children'] = []; self_items = items[path_end[i]].children; self_result = result[i]['children']; }; }else{ if(i !== path_end.length-1){ //not to the end self_result[0] = {}; self_result[0]['name'] = self_items[path_end[i]].name; self_result[0]['id'] = self_items[path_end[i]].id; self_result[0]['children'] = []; self_items = self_items[path_end[i]].children; self_result = self_result[0]['children']; }else{ //to the end, check for the children end self_result[0] = {}; self_result[0]['name'] = self_items[path_end[i]].name; self_result[0]['id'] = self_items[path_end[i]].id; if(self_items[path_end[i]].children){ self_result[0]['chidren'] = self_items[path_end[i]].children; }; //check again the searching, if not match the name_to_search, set result to empty! if(self_result[0]['name'] !== name_to_search){ result = []; } }; } }; }else{ result = []; } console.log(result);
The below solution uses object-scan .
Notes: (1) Input is not mutated (2) Well behaved input of form array -> children
is expected.
// const objectScan = require('object-scan'); const finder = (name, input) => objectScan(['**(^children$).name'], { abort: true, useArraySelector: false, filterFn: ({ key, value, context, parents }) => { if (value !== name) { return false; } let cur = context; for (let idx = 0; idx < key.length - 1; idx += 1) { const segment = key[idx]; if (idx % 2 === 0) { cur.push({ ...parents[parents.length - 1 - idx][segment] }); cur = cur[0]; } else { cur[segment] = []; cur = cur[segment]; } } return true; } })(input, []); const items = [{ name: 'a1', id: 1, children: [{ name: 'a2', id: 2, children: [{ name: 'a3', id: 3 }] }, { name: 'b2', id: 5, children: [{ name: 'a4', id: 4 }] }] }]; console.log(finder('a2', items)); // => [ { name: 'a1', id: 1, children: [ { name: 'a2', id: 2, children: [ { name: 'a3', id: 3 } ] } ] } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>
Disclaimer : I'm the author of object-scan
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.