简体   繁体   中英

search in JSON tree with full structure intect

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM