在具有完整结构的JSON树中搜索

时间:2018-09-26 13:41:08

标签: javascript json node.js search filter

我认为在filter nested tree object without losing structure

之前曾有人问过我

但是我要寻找的却与此相反。

对于JSON数据

    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
            }]
        }]
    }
];

我们需要过滤器,以便您搜索a2。它应该返回以下内容

var items = [
{
    name: "a1",
    id: 1,
    children: [{
        name: "a2",
        id: 2,
        children: [{
            name: "a3",
            id: 3
        }]
    }]
}

];

即该树路径中的所有节点(从根到叶节点)。

有什么想法要在nodejs / javascript中实现吗?

谢谢

2 个答案:

答案 0 :(得分:0)

按照我的示例,您可以更改代码以适合您的作品:

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);

答案 1 :(得分:0)

以下解决方案使用object-scan

注意:(1)输入未突变(2)期望输入object-scan形式的行为良好。

如果性能很重要,则可以(1)分隔breakFn的编译和搜索部分,然后(2)context.length !== 0与{ {1}}。

const objectScan = require('object-scan');

const finder = (name, input) => objectScan(['**(^children$).name'], {
  useArraySelector: false,
  filterFn: ({ key, value, context, parents }) => {
    if (value !== name || context.length !== 0) {
      return;
    }
    const result = [];
    let cur = result;
    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];
      }
    }
    context.push(result);
  }
})(input, [])[0];

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(JSON.stringify(finder('a2', items)));
// => [{"name":"a1","id":1,"children":[{"name":"a2","id":2,"children":[{"name":"a3","id":3}]}]}]