按字符串值过滤嵌套对象数组

Filtering an array of nested objects by string value

我正在尝试使用嵌套对象过滤数组,如下所示:

const items = [
    {
        "id": 1,
        "name": "test1",
        "subitems": [
            {
                "id": 2,
                "name": "test2",
                "subsubitems": [
                    {
                        "id": 3,
                        "name": "test3",
                    },
                    {
                        "id": 4,
                        "name": "test4",
                    }
                ]
            }
        ]
    },
    {
        "id": 10,
        "name": "test10",
        "subitems": [
            {
                "id": 20,
                "name": "test20",
                "subsubitems": [
                    {
                        "id": 30,
                        "name": "test30",
                    }
                ]
            }
        ]
    }
]

const filteredResults = items.filter((item) =>
    item.subitems.some((subitem) =>
        subitem.subsubitems.some((subsubitem) =>
            subsubitem.name.includes('test3')
        )
    )
)

console.log(filteredResults)

但过滤不正确,原始数组正在 returned。现在我只是试图在子项级别进行过滤。最终我想要 return 一个数组,其中包含任何级别的任何匹配项。

所以 test2 会 return 一个这样的数组:

[
    {
        "id": 1,
        "name": "test1",
        "subitems": [
            {
                "id": 2,
                "name": "test2",
                "subsubitems": [
                    {
                        "id": 3,
                        "name": "test3",
                    },
                    {
                        "id": 4,
                        "name": "test4",
                    }
                ]
            }
        ]
    }
]

test3 会 return 一个这样的数组:

[
    {
        "id": 1,
        "name": "test1",
        "subitems": [
            {
                "id": 2,
                "name": "test2",
                "subsubitems": [
                    {
                        "id": 3,
                        "name": "test3",
                    }
                ]
            }
        ]
    },
    {
        "id": 10,
        "name": "test10",
        "subitems": [
            {
                "id": 20,
                "name": "test20",
                "subsubitems": [
                    {
                        "id": 30,
                        "name": "test30",
                    }
                ]
            }
        ]
    }
]

并且 test 会 return 一切。

您可以使用一个函数来检查实际级别并搜索子级别,如果子级别有长度,则将实际级别作为结果。

const
    filter = childrenKey => o => {
        if (o.name === value) return o;
        const childrenValues = (o[childrenKey] || []).flatMap(filter('sub' + childrenKey));
        return childrenValues.length ? { ...o, [childrenKey]: childrenValues } : [];
    },
    data = [{ id: 1, name: "test1", subitems: [{ id: 2, name: "test2", subsubitems: [{ id: 3, name: "test3" }, { id: 4, name: "test4" }] }] }, { id: 10, name: "test10", subitems: [{ id: 20, name: "test20", subsubitems: [{ id: 30, name: "test30" }] }] }],
    value = 'test3',
    result = data.flatMap(filter('subitems'));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

如果我没理解错的话,流程是:

  1. 如果当前级别的 name 包含搜索值,则将当前级别和所有可用的 subitemssubsubitems 数组中的子级包含在内。
  2. 否则,对 subitemssubsubitems 数组中可用的每个项目重复相同的检查,如果有任何结果,则包括当前项目。

我认为以下示例会让您产生这种行为。请注意,在搜索“test2”时,名称为“test3”和“test4”的项目包含在您的问题中。此外,包含“test20”是因为除了 subsubitems 级别外,它还在 subitems 级别进行搜索,并且“test20”包括“test2”。

const items = [
  { id: 1, name: "test1", subitems: [
    { id: 2, name: "test2", subsubitems:[
      { id: 3, name: "test3" },
      { id: 4, name: "test4" }
    ]}
  ]},
  { id: 10, name: "test10", subitems: [
    { id: 20, name: "test20", subsubitems: [
      { id: 30, name: "test30"}
    ]}
  ]}
];

const deepFilter = (items, value) => items.reduce((arr, cur) => {
  if (cur.name.includes(value)) arr.push(cur);
  else if (cur.hasOwnProperty('subitems')) {
    const subItems = deepFilter(cur.subitems, value);
    if (subItems.length) {
      cur.subitems = subItems;
      arr.push(cur);
    }
  }
  else if (cur.hasOwnProperty('subsubitems')) {
    const subSubItems = deepFilter(cur.subsubitems, value);
    if (subSubItems.length) {
      cur.subsubitems = subSubItems;
      arr.push(cur);
    }
  }
  return arr;
}, []);

console.log('test2:');
console.log(deepFilter(items, 'test2'));

console.log('test3:');
console.log(deepFilter(items, 'test3'));
.as-console-wrapper { max-height: 100% !important; top: 0; }