过滤嵌套的 JSON 对象

IT技术 reactjs nested-loops
2022-07-16 08:31:51

I have a search bar where you type employee name and it should return the name based on a filter. I have a nested JSON object (as shown below) where I need to drill into the object to access the employee's names in the array.

You can see the multiple options I tried to implement (they are commented out) My problem is the code is not filtering the names and returning all the names not the names searched for. I get this error TypeError: Cannot read property 'filter' of undefined

The following code works to access the employee names in another component:

{test.map((result) => (result.details.map((innerArr) => 
  <h5>{innerArr.employee}</h5>
  )))}

how can I implement the above in the below code

      const SearchByEmpComp = () => {
      const [company, setCompany] = useState([
    {
      "company": "HIJ",
      "_id": "610aeaec618ac5902c466541",
      "details": 
      [
          {
              "employee": "Lesley Peden",
              "notes": "Lesley's note",
              "_id": "610aeaec618ac5902c466542"
          },
          {
              "employee": "Wayne Smith",
              "notes": "Wayne's note",
              "_id": "610aeaec618ac5902c466543"
          }
      ],
    },
    {
     "company": "ABC",
     "_id": "61003ff8e7684b709cf10da6",
     "details": 
      [
         {
             "employee": "David Barton",
             "notes": "some note!!",
             "_id": "610aebb2618ac5902c46654e"
         }
      ],
   }
]);
    
  //below code does not work
  //attemp 1
      const test = company.filter((r) => 
      r.details.map((innerArr) => {
      return innerArr.employee.toLowerCase().includes
      (searchField.toLowerCase());
  })
  );
  
  //attemp 1
  //   const test = company.map((el) => {
  //   return {...element, detail: element.detail.filter((details) => 
  //   details.employee.toLowerCase().includes
  //   (searchField.toLowerCase()))}
  //   })

  //attemp 2      
  //   const test = company.filter((res) => {
  //   return res.details.map((innerArr) =>
  //   innerArr.employee.toLowerCase().includes
  //   (searchField.toLowerCase()));
  //  });

  
  //attemp 3
  //   const test = company.filter((comp) =>
  //   comp.details.employee.toLowerCase().includes(searchField.toLowerCase())
  //   );

  const deatils = () => {
    if (searchShow) 
      return <EmpDetailsByName test={test} />
    }
  };

return (
    <>
    <FormControl
      type="search"
      placeholder="Type Customer Name Here"
    />
      <div>
        <Button
          onClick={handleClick}
        >
          Enter
        </Button>
        <div>{deatils()}</div>
      </div
  );
};

code to render names

 const EmpDetailsByName = ({ test }) => {
  return (
    <>
  {test.map((result) => 
  (result.details.map((innerArr) => 
   <h5>{innerArr.employee}</h5>
  )))}
    </>
  );
};
export default EmpDetailsByName;
4个回答

除了 Werlious 的回答,如果您正在寻找仍被包括在内的公司,那么您可以按此处所示进行映射。第一个映射仍将返回已过滤掉所有员工的公司。第二个映射将过滤掉没有任何细节的公司。

第三种是只返回员工的更现代的方法。但是有无数的变化可以用来做这件事。

const company = [
  {
    company: "HIJ",
    _id: "610aeaec618ac5902c466541",
    details: [
      {
        employee: "Lesley Peden",
        notes: "Lesley's note",
        _id: "610aeaec618ac5902c466542",
      },
      {
        employee: "Wayne Smith",
        notes: "Wayne's note",
        _id: "610aeaec618ac5902c466543",
      },
    ],
  },
  {
    company: "ABC",
    _id: "61003ff8e7684b709cf10da6",
    details: [
      {
        employee: "Lesley Peden",
        notes: "some note!!",
        _id: "610aebb2618ac5902c46654e",
      },
    ],
  },
];
const searchField = "les";
//attemp 1
const test = company.map((element) => {
  return {
    ...element,
    details: element.details.filter((details) =>
      details.employee.toLowerCase().includes(searchField.toLowerCase())
    ),
  };
});
console.log("test", test);

const test2 = company
  .map((company) => {
    let details = company.details.filter((detail) =>
      detail.employee.toLowerCase().includes(searchField.toLowerCase())
    );
    if (!details.length) {
      return null;
    }
    return { ...company, details };
  })
  .filter(Boolean);

console.log("test2", test2);

// Modern browser version of filtering to only the employees :)
const test3 = company.flatMap((company) =>
  company.details.filter((detail) =>
    detail.employee.toLowerCase().includes(searchField.toLowerCase())
  )
);
console.log("test3", test3);

我举了一个例子,说明如何使用输入文本过滤 json

示例过滤器 Json

看看状态的使用以及如何访问公司

所以我有一个使用正则表达式的简单解决方案,

employeeArray = [
  {
    company: "HIJ",
    _id: "610aeaec618ac5902c466541",
    details: [
      {
        employee: "Lesley Peden",
        notes: "Lesley's note",
        _id: "610aeaec618ac5902c466542",
      },
      {
        employee: "Wayne Smith",
        notes: "Wayne's note",
        _id: "610aeaec618ac5902c466543",
      },
    ],
  },
  {
    company: "ABC",
    _id: "61003ff8e7684b709cf10da6",
    details: [
      {
        employee: "David Barton",
        notes: "some note!!",
        _id: "610aebb2618ac5902c46654e",
      },
    ],
  },
];


// Set the state of the search string using state
let searchUser = "Les";

// converting the search string to regex
let convertedName = new RegExp(`.*${searchUser}.*`);

searchResults = employeeArray
  .map((element) => {
    return {
      ...element,
      details: element.details.filter((employee) => {
        // Filtering based on the Regex
        return convertedName.test(employee.employee);
      }),
    };
  })
  //   filtering based on the length of the data array length
  .filter((element) => element.details.length > 0);

console.log(searchResults);


解释:所以根据你的情况,

  • 我们首先获取用户输入,然后将它们转换为正则表达式,这样我们就可以得到名称的所有推荐。
  • 过滤器,所以对于Array.map,我们首先将高级映射直接应用于数组,然后我们关注内部细节数组并为此应用过滤器,并且我已经根据数据的存在返回一个布尔值,
  • 所以我们要做的是 MAP-> [OBJECTS -> [FILTER[DETAILS]]],所以,现在我们过滤每个 JSON 中的每个细节数组,然后我们根据细节数组的长度过滤它们所以,我们终于得到了完整的对象。结果将如预期的那样。

搜索字符串的输出设置为“LES”

[
{
  company: 'HIJ',
  _id: '610aeaec618ac5902c466541',
  details: [
    {
      employee: 'Lesley Peden',
      notes: "Lesley's note",
      _id: '610aeaec618ac5902c466542'
    }
  ]
}
]

这将帮助您提出给定名称的所有建议。一个数组[对象]

我不知道您的过滤器是如何应用的(它甚至过滤什么?公司?ID?),但实际上搜索功能应该是它自己的小片段,正如评论所建议的那样。

function SearchJsonForName(json,name) {
    let result = []
    for(company of json) {
        for(employee of company.details) {
            if(employee.name.match(name)) result.push(employee.name);  
        }
    }
    return result
}

那应该让你开始。如果您需要应用过滤器(也许过滤公司?),您应该在搜索数组之前应用它(或者修改函数以使用过滤器;>)。

对于修改数组的版本:

function FilterByName(json,name) {
    return json.map(company => {
        let result = company.details.filter(employee => 
employee.name.match(name)));
        return result.length > 0 ? {...company,details:result} : false;
    }).filter(good => good);
};