使用对象数组过滤嵌套的 JSON 个对象
Filter nested JSON objects with an array of objects
我有一个搜索栏,您可以在其中输入员工姓名,它应该 return 基于过滤器的姓名。我有一个嵌套的 JSON 对象(如下所示),我需要在其中钻取该对象以访问数组中的员工姓名。
我的问题是代码没有过滤名称并且 returning 所有名称而不是搜索的名称。我收到此错误 TypeError: Cannot read property 'filter' of undefined
问题:我需要映射元素两次,我该怎么做?
更新:没有答案对我有帮助。第二个答案与查询有关,对于我正在寻找的简单答案来说非常复杂,第一个答案的数据结构与我的不同。
第二次更新: 点击
我还将其添加到下面的线程
为了更清楚,添加了以下内容
我尝试了什么:
const results = company.filter((comp) =>
comp.details.employee.toLowerCase().includes(searchField.toLowerCase())
);
const results = company.map((el) => {
return {...el, dets: el.dets.filter((details) =>
details.employee.toLowerCase().includes(searchField.toLowerCase()))}
})
const results = company.filter((comp) => r.details.map((innerArr) => {
return innerArr.employee.toLowerCase().includes(searchField.toLowerCase());
})
);
const results = company.filter((comp) => {
return res.details.map((inner) =>
inner.employee.toLowerCase().includes(searchField.toLowerCase())
);
});
为了更清楚,添加了以下内容
以下代码用于访问另一个组件中的员工姓名:我如何在下面的代码中实现上述内容
{test.map((result) => (result.details.map((innerArr) =>
<h5>{innerArr.employee}</h5>
)))}
const SearchByEmpComp = () => {
const [company, setCompany] = useState([
{
"company": "HIJ",
"_id": "1",
"details":
[
{
"employee": "Lesley Peden",
"notes": "Lesley's note",
"_id": "2"
}
],
},
{
"company": "ABC",
"_id": "3",
"details":
[
{
"employee": "David Barton",
"notes": "some note!!",
"_id": "4"
}
],
}
]);
//below code I need to edit with nested map
const test = company.filter((r) =>
r.details.map((innerArr) => {
return innerArr.employee.toLowerCase().includes
(searchField.toLowerCase());
})
);
const deatils = () => {
if (searchShow)
return <EmpDetailsByName test={test} />
}
};
return (
<>
<FormControl
type="search"
/>
<div>
<Button
onClick={handleClick}
>
Enter
</Button>
<div>{deatils()}</div>
</div
);
};
像这样的东西应该可以工作:
const searchField = 'Les';
const company = [
{
company: 'ABC',
details: [
{
employee: 'Lesley Peden',
_id: 2
}
]
},
{
company: 'EFG',
details: [
{
employee: 'Wayne Smith',
_id: 2
}
]
},
];
const results = company.find(comp =>
comp.details.filter(inner =>
inner.employee.toLowerCase().includes(searchField.toLowerCase())
));
console.log(results);
并在 HTML 中以类似的方式打印出来。
OP 的 company
数组语法确实有问题,尤其是 details
数组。
我想后者将包含许多员工项目;其他任何东西都没有意义。
此外,Jane Smith
或 John Doe
每个公司都必须恰好存在一次,但当然每个公司都可能同时出现在多个公司中。这也是一个真实世界的用例。
因此,假设正确的数据源格式看起来更像...
[{
company: "ABC",
details: [{
employee: "Lesley Peden",
_id: 1,
}, {
employee: "John Doe",
_id: 2,
}, {
employee: "Jane Smith",
_id: 3,
}],
}, {
company: "EFG",
details: [{
employee: "John Doe",
_id: 1,
}, {
employee: "Jane Smith",
_id: 2,
}, {
employee: "Wayne Smith",
_id: 3,
}],
}];
因此,一种方法必须从每个 公司项目的 员工项目 中收集并规范化 details
数组。为了不失去与其公司项目任何员工项目[的关系=74=] 确实被分配了相关公司。
这发生在初始映射和标准化项目创建过程中。 员工项目,如 { employee: "Lesley Peden", _id: 1 }
,属于 公司项目 company: "ABC"
被临时映射到标准化的 公司员工项目 ... { "companyName": "ABC", "employeeId": 1, "employee": "Lesley Peden" }
.
在第二个 aggregation/reducer 步骤中,这个标准化 公司员工项目 的临时列表被转换为 [=基于 49=]employee name
的项目,其中每个项目都有一个额外的 companies
数组,它反映了 一个名字到许多公司的关系,不仅包含一个,而且可能更多company items 对于像 John Doe
这样的名字很可能看起来像这样...
{
name: "John Doe",
companies: [{
companyName: "ABC",
employeeId: 2,
}, {
companyName: "EFG",
employeeId: 1,
}],
}
通过(碎片化的)名称搜索查询,每个项目的 name
属性 可以轻松过滤此类原因项目的数组,下面的方法将通过一些可执行示例代码来演示......
function createEmployeeWithBoundCompanyData({ _id:employeeId, ...employeeValue }) {
return { ...this, employeeId, ...employeeValue };
}
function aggregateEmployeeItems(collector, companyEmployee) {
const { employee:name, ...employeeValue } = companyEmployee;
const { index, list } = collector;
const employeeItem = index[name] ??= { name, companies: [] };
if (employeeItem.companies.length === 0) {
list.push(employeeItem);
}
employeeItem.companies.push(employeeValue);
return collector;
}
function collectCompanyEmployees(employeeList, companyItem) {
const { company:companyName, _id:companyId, details } = companyItem;
return employeeList.concat(
details.map(
createEmployeeWithBoundCompanyData,
{ companyName, companyId },
)
);
}
function createListOfCompanyEmployees(companyListsOfEployees) {
return companyListsOfEployees
.reduce(collectCompanyEmployees, [])
.reduce(aggregateEmployeeItems, { index: {}, list: [] }).list;
}
function queryCompanyEmployeesByName(companyListsOfEployees, query) {
return createListOfCompanyEmployees(companyListsOfEployees)
.filter(({ name }) =>
name.trim().toLowerCase().includes(
query.trim().toLowerCase()
)
);
}
console.log(
'createListOfCompanyEmployees(companyList) ...',
createListOfCompanyEmployees(companyList)
);
console.log(
"queryCompanyEmployeesByName(companyList, 'Smith') ...",
queryCompanyEmployeesByName(companyList, 'Smith')
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
const companyList = [{
company: "ABC",
_id: "aaaa-bbbb-cccc-0000",
details: [{
employee: "Lesley Peden",
notes: "some notes about Lesley Peden",
_id: "aaaa-bbbb-cccc-0001",
}, {
employee: "John Doe",
notes: "some notes about John Doe",
_id: "aaaa-bbbb-cccc-0002",
}, {
employee: "Jane Smith",
notes: "some notes about Jane Smith",
_id: "aaaa-bbbb-cccc-0003",
}],
}, {
company: "EFG",
_id: "dddd-eeee-ffff-0000",
details: [{
employee: "John Doe",
notes: "some notes about John Doe",
_id: "dddd-eeee-ffff-0001",
}, {
employee: "Jane Smith",
notes: "some notes about Jane Smith",
_id: "dddd-eeee-ffff-0002",
}, {
employee: "Wayne Smith",
notes: "some notes about Wayne Smith",
_id: "dddd-eeee-ffff-0003",
}],
}];
</script>
所有功劳归功于 Zachary Haber:
这是我的问题的正确解决方案
const test = company.map((element) => {
return {
...element,
details: element.details.filter((details) =>
details.employee.toLowerCase().includes(searchField.toLowerCase())
),
};
});
我有一个搜索栏,您可以在其中输入员工姓名,它应该 return 基于过滤器的姓名。我有一个嵌套的 JSON 对象(如下所示),我需要在其中钻取该对象以访问数组中的员工姓名。
我的问题是代码没有过滤名称并且 returning 所有名称而不是搜索的名称。我收到此错误 TypeError: Cannot read property 'filter' of undefined
问题:我需要映射元素两次,我该怎么做?
更新:没有答案对我有帮助。第二个答案与查询有关,对于我正在寻找的简单答案来说非常复杂,第一个答案的数据结构与我的不同。
第二次更新: 点击
为了更清楚,添加了以下内容 我尝试了什么:
const results = company.filter((comp) =>
comp.details.employee.toLowerCase().includes(searchField.toLowerCase())
);
const results = company.map((el) => {
return {...el, dets: el.dets.filter((details) =>
details.employee.toLowerCase().includes(searchField.toLowerCase()))}
})
const results = company.filter((comp) => r.details.map((innerArr) => {
return innerArr.employee.toLowerCase().includes(searchField.toLowerCase());
})
);
const results = company.filter((comp) => {
return res.details.map((inner) =>
inner.employee.toLowerCase().includes(searchField.toLowerCase())
);
});
为了更清楚,添加了以下内容 以下代码用于访问另一个组件中的员工姓名:我如何在下面的代码中实现上述内容
{test.map((result) => (result.details.map((innerArr) =>
<h5>{innerArr.employee}</h5>
)))}
const SearchByEmpComp = () => {
const [company, setCompany] = useState([
{
"company": "HIJ",
"_id": "1",
"details":
[
{
"employee": "Lesley Peden",
"notes": "Lesley's note",
"_id": "2"
}
],
},
{
"company": "ABC",
"_id": "3",
"details":
[
{
"employee": "David Barton",
"notes": "some note!!",
"_id": "4"
}
],
}
]);
//below code I need to edit with nested map
const test = company.filter((r) =>
r.details.map((innerArr) => {
return innerArr.employee.toLowerCase().includes
(searchField.toLowerCase());
})
);
const deatils = () => {
if (searchShow)
return <EmpDetailsByName test={test} />
}
};
return (
<>
<FormControl
type="search"
/>
<div>
<Button
onClick={handleClick}
>
Enter
</Button>
<div>{deatils()}</div>
</div
);
};
像这样的东西应该可以工作:
const searchField = 'Les';
const company = [
{
company: 'ABC',
details: [
{
employee: 'Lesley Peden',
_id: 2
}
]
},
{
company: 'EFG',
details: [
{
employee: 'Wayne Smith',
_id: 2
}
]
},
];
const results = company.find(comp =>
comp.details.filter(inner =>
inner.employee.toLowerCase().includes(searchField.toLowerCase())
));
console.log(results);
并在 HTML 中以类似的方式打印出来。
OP 的 company
数组语法确实有问题,尤其是 details
数组。
我想后者将包含许多员工项目;其他任何东西都没有意义。
此外,Jane Smith
或 John Doe
每个公司都必须恰好存在一次,但当然每个公司都可能同时出现在多个公司中。这也是一个真实世界的用例。
因此,假设正确的数据源格式看起来更像...
[{
company: "ABC",
details: [{
employee: "Lesley Peden",
_id: 1,
}, {
employee: "John Doe",
_id: 2,
}, {
employee: "Jane Smith",
_id: 3,
}],
}, {
company: "EFG",
details: [{
employee: "John Doe",
_id: 1,
}, {
employee: "Jane Smith",
_id: 2,
}, {
employee: "Wayne Smith",
_id: 3,
}],
}];
因此,一种方法必须从每个 公司项目的 员工项目 中收集并规范化 details
数组。为了不失去与其公司项目任何员工项目[的关系=74=] 确实被分配了相关公司。
这发生在初始映射和标准化项目创建过程中。 员工项目,如 { employee: "Lesley Peden", _id: 1 }
,属于 公司项目 company: "ABC"
被临时映射到标准化的 公司员工项目 ... { "companyName": "ABC", "employeeId": 1, "employee": "Lesley Peden" }
.
在第二个 aggregation/reducer 步骤中,这个标准化 公司员工项目 的临时列表被转换为 [=基于 49=]employee name
的项目,其中每个项目都有一个额外的 companies
数组,它反映了 一个名字到许多公司的关系,不仅包含一个,而且可能更多company items 对于像 John Doe
这样的名字很可能看起来像这样...
{
name: "John Doe",
companies: [{
companyName: "ABC",
employeeId: 2,
}, {
companyName: "EFG",
employeeId: 1,
}],
}
通过(碎片化的)名称搜索查询,每个项目的 name
属性 可以轻松过滤此类原因项目的数组,下面的方法将通过一些可执行示例代码来演示......
function createEmployeeWithBoundCompanyData({ _id:employeeId, ...employeeValue }) {
return { ...this, employeeId, ...employeeValue };
}
function aggregateEmployeeItems(collector, companyEmployee) {
const { employee:name, ...employeeValue } = companyEmployee;
const { index, list } = collector;
const employeeItem = index[name] ??= { name, companies: [] };
if (employeeItem.companies.length === 0) {
list.push(employeeItem);
}
employeeItem.companies.push(employeeValue);
return collector;
}
function collectCompanyEmployees(employeeList, companyItem) {
const { company:companyName, _id:companyId, details } = companyItem;
return employeeList.concat(
details.map(
createEmployeeWithBoundCompanyData,
{ companyName, companyId },
)
);
}
function createListOfCompanyEmployees(companyListsOfEployees) {
return companyListsOfEployees
.reduce(collectCompanyEmployees, [])
.reduce(aggregateEmployeeItems, { index: {}, list: [] }).list;
}
function queryCompanyEmployeesByName(companyListsOfEployees, query) {
return createListOfCompanyEmployees(companyListsOfEployees)
.filter(({ name }) =>
name.trim().toLowerCase().includes(
query.trim().toLowerCase()
)
);
}
console.log(
'createListOfCompanyEmployees(companyList) ...',
createListOfCompanyEmployees(companyList)
);
console.log(
"queryCompanyEmployeesByName(companyList, 'Smith') ...",
queryCompanyEmployeesByName(companyList, 'Smith')
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
const companyList = [{
company: "ABC",
_id: "aaaa-bbbb-cccc-0000",
details: [{
employee: "Lesley Peden",
notes: "some notes about Lesley Peden",
_id: "aaaa-bbbb-cccc-0001",
}, {
employee: "John Doe",
notes: "some notes about John Doe",
_id: "aaaa-bbbb-cccc-0002",
}, {
employee: "Jane Smith",
notes: "some notes about Jane Smith",
_id: "aaaa-bbbb-cccc-0003",
}],
}, {
company: "EFG",
_id: "dddd-eeee-ffff-0000",
details: [{
employee: "John Doe",
notes: "some notes about John Doe",
_id: "dddd-eeee-ffff-0001",
}, {
employee: "Jane Smith",
notes: "some notes about Jane Smith",
_id: "dddd-eeee-ffff-0002",
}, {
employee: "Wayne Smith",
notes: "some notes about Wayne Smith",
_id: "dddd-eeee-ffff-0003",
}],
}];
</script>
所有功劳归功于 Zachary Haber: 这是我的问题的正确解决方案
const test = company.map((element) => {
return {
...element,
details: element.details.filter((details) =>
details.employee.toLowerCase().includes(searchField.toLowerCase())
),
};
});