递归过滤搜索栏的 json 数据

recursively filter json data for search bar

我正在尝试编写搜索栏过滤器以响应 table。

困难的部分是JSON数据结构,它可能具有未知深度的父子关系,例如:

  data = [
    {
      input: "row 0 ",
      output: "output of the first row"
      subRows: [],
    },
    {
      input: "row 1",
      output: "output of the second row"
      subRows: [
        {
          input: "third row 1.0",
          output: "output of the 3° row"
          subRows: [
            {
              input: "row 1.0.0",
              output: "output of the third row"
              subRows: [],
            },
          ],
        },
        {
          input: "row 1.1",
          output: "output of 2 rows after the third (fifth)"
          subRows: []
        },
      ],
    },
  ];

附加信息:上面的每个对象 JSON 在我的 html(jsx) table 中表示为一行,他的子行是其他行,可以通过用户点击。

我以为我可以用 ES6 的过滤函数来处理它,但我不知道怎么做。

这是我期望的结果,如果用户在搜索栏中输入例如:“third”

        {
          input: "third row 1.0",
          output: "output of the 3° row"
          subRows: []
        },
        {
          input: "row 1.1",
          output: "output of 2 rows after the third (fifth)",
          subRows: []
        },

这是我的代码:

 const updateFilter = (filterValue) => {
   let results = data.filter(function f(row) {
      if (Object.values(row).includes(filterValue.toLowerCase())) {
        return true;
      }
      if (row.subRows && row.subRows.length > 0) {
        return (row.subRows = row.subRows.filter(f));
      }
    });
    console.log(JSON.stringify(results));
  };
 }

这里是codePen中的代码:https://codepen.io/ardiz90/pen/yLajjRQ?editors=0012

感谢您的帮助!

编辑:原来我无法展平行,因为 table 需要树结构中的数据才能呈现它,所以下面写的展平行的解决方案不是可行..

您可以先展平嵌套对象,然后相应地过滤值。我还认为您使用 Object.values(...).includes(...) 的过滤机制无法正常工作。

这是一个展平对象并过滤它们的示例:

// returns a Array containing the element itself and its children recursively
function flattenWithSubRows(entries) {
    return entries.flatMap(entry => [
        entry, ...flattenWithSubRows(entry.subRows)
    ]);
}

// gets an array containing only the objects 
// containing the searchString in a string property
function getAllMatchingItems(searchString, array) {
    const isMatching = entry => Object.values(entry)
        .filter(val => typeof val === 'string')
        .map(val => val.toLowerCase())
        .some(val => val.includes(searchString.toLowerCase()));

    return flattenWithSubRows(array).filter(isMatching)
}

const filtered = getAllMatchingItems("third", data);
console.log(filtered);