Here is a sample of my JSON.
const data = [{
"employees": [
{
"employee": [
{
"name": "Jon",
"surname": "Smith",
"leaveRequest": [
{
"id": "3000",
"approver": "Terry"
}
]
}],
},
{
"employee": [
{
"name": "Mike",
"surname": "Jones",
"leaveRequest": [
{
"id": "1700",
"approver": "Mary"
}
]
},
]
}
]
}];
I want to be able to search by id across all leaveRequests and get the employee's name and surname.
If I pass id "3000" I would like to be able to get an object ["name": "Jon", "surname": "Smith"]
I've tried implementing the solution from: How to get immediate parent Id of the child id in array of nested json Object?
This is what I've tried:
const findEmployee = (arr, id) => {
for (let i = 0; i < arr.length; i ) {
if (arr[i].id === id) {
return [];
}
else if (arr[i].employee && arr[i].employee.length) {
const t = findEmployee(arr[i].employee, id);
if (t !== false) {
if (t.length == 0)
t.push({"name": arr[i].name, "surname": arr[i].surname});
return t;
}
}
}
return false;
};
console.log(findEmployee(data, "3000"))
But the solution in that thread relies on each child node having the same key 'children' which wouldn't work in my scenario. I'd have to restructure my JSON structure to be:
employee
employee
employee
id
And this doesn't make sense in my scenario. How can I search by id across all leaveRequests and get the employee's name and surname from the immediate parent?
CodePudding user response:
I'd suggest walking through the object recursively, and returning if we find an object with a leaveRequest
property.
Once we find this we'll strip off the leaveRequest and return the rest of the object.
const data = [{ "employees": [ { "employee": [ { "name": "Jon", "surname": "Smith", "leaveRequest": [ { "id": "3000", "approver": "Terry" } ] }], }, { "employee": [ { "name": "Mike", "surname": "Jones", "leaveRequest": [ { "id": "1700", "approver": "Mary" } ] }, ] } ] }];
function findRequest(input, id) {
if (input.leaveRequest && input.leaveRequest[0].id == id) {
// Return everything bar the leave request...
return (({ leaveRequest, ...obj}) => obj)(input);
}
for(let k in input) {
if (input[k] && typeof(input[k]) === 'object') {
let leaveRequest = findRequest(input[k], id);
if (leaveRequest) return leaveRequest;
}
}
}
let ids = [1700, 3000];
ids.forEach(id => console.log('id: ', id, '\nrequest:', findRequest(data, id)));
.as-console-wrapper { max-height: 100% !important; }
CodePudding user response:
Here is an answer using object-scan:
.as-console-wrapper {max-height: 100% !important; top: 0}
<script type="module">
import objectScan from 'https://cdn.jsdelivr.net/npm/[email protected]/lib/index.min.js';
const data = [{ employees: [{ employee: [{ name: 'Jon', surname: 'Smith', leaveRequest: [{ id: '3000', approver: 'Terry' }] }] }, { employee: [{ name: 'Mike', surname: 'Jones', leaveRequest: [{ id: '1700', approver: 'Mary' }] }] }] }];
const find = objectScan(['[*].employees[*].employee[*].leaveRequest[*].id'], {
abort: true, // abort after first result
filterFn: ({ value, context }) => value === context, // find the correct id
rtn: ({ parents }) => parents[2] // return the correct node
});
console.log(find(data, '3000'));
// => { name: 'Jon', surname: 'Smith', leaveRequest: [ { id: '3000', approver: 'Terry' } ] }
</script>
Disclaimer: I'm the author of object-scan