Context I am using: Windows 11, VSCode and node v18.12.1
The code I am working on is trying to traverse several JSON objects. Then, using an array variable, the code needs to filter on certain attributes in each object, as there is more than one value that needs to filter against in each name attribute in each object.
Question The following code is working which traverses all levels of all objects and logs the person’s name, city and employer. What it needs to do is also filter out all objects that match one or more of the names in the filteredNames array, and then return all objects where they don’t contain these names.
Here is the code that’s working (as per above):
let data = [{ "Pagination": { "NumberOfPeople": 185, "PageSize": 200, "PageNumber": 1, "NumberOfPages": 1 }, "People": [ { "name": "TJ", "job": "Software Engineer", "organization": { "company": { "employer": "amazon", "department": "IT" } }, "location": { "city": "Boston", "state": "Massachusetts" } }, { "name": "Dominique", "job": "CEO", "organization": { "company": { "employer": "IBM", "department": "IT" } }, "city": "Seattle", "state": "Washington", }, { "name": "Enrique", "job": "Engineer", "organization": { "company": { "employer": "Bellkrieg Megasystems", "department": "Construction" } }, "location": { "address": { "state": "New York", "city": "New York City", "zip": "11323" } } }, { "name": "Bob", "job": "Project Manager", "organization": { "company": { "employer": "Megasystems", "department": "R&D" } }, "address": { "location": { "quadrant": { "block": 1, "state": "Texas", "city": "Austin" } } } } ]}] data.filter(item => { iterateObject(item); }); function iterateObject(obj) { for(prop in obj) { if(typeof(obj[prop]) == "object"){ iterateObject(obj[prop]); } else { if(prop == "name" || prop == "city" || prop == "employer") { console.log(prop.toUpperCase() + ': ', obj[prop]); } //some code goes here which if either of filteredEmployers is in 'employer', nesting position agnostic, i.e. the attribute could be nested deeper or shallower in the object, //then print out all objects which don't contain any of the attributes in filteredEmployers array } } }
which gives the result:
NAME: TJ EMPLOYER: amazon CITY: Boston NAME: Dominique EMPLOYER: IBM CITY: Seattle NAME: Enrique EMPLOYER: Bellkrieg Megasystems CITY: New York City NAME: Bob EMPLOYER: Megasystems CITY: Austin
Using an array variable, it needs to filter on ‘Megasystems’ and ‘Bellkrieg’ as an array in each object’s employer attribute, as there is more than one value that needs to be filtered against. It will also make it more adaptable, so it will be relatively easy to add to the filteredEmployers, as and when it’s required…
What I’ve tried I’ve searched various other solutions for the issue encountered, but they don’t seem to cater for what is needed…
This is what I currently have…
//data of nested objects goes here filteredEmployers = ['Megasystems', 'Bellkrieg']; data.filter(item => { iterateObject(item); }); function iterateObject(obj) { for(prop in obj) { if(typeof(obj[prop]) == "object"){ iterateObject(obj[prop]); } else { checkPeople = Object.values(data).filter(({employer}) => !filteredEmployers.some(filtered => employer?.match(filtered))); if(checkPeople !== null) { console.log(checkPeople);} } } } }
However, it gives the following:
[ { Pagination: { NumberOfPeople: 185, PageSize: 200, PageNumber: 1, NumberOfPages: 1 }, People: [ [Object], [Object], [Object], [Object] ] } ] [ { Pagination: { NumberOfPeople: 185, PageSize: 200, PageNumber: 1, NumberOfPages: 1 }, People: [ [Object], [Object], [Object], [Object] ] } ] [ { Pagination: { NumberOfPeople: 185, PageSize: 200, PageNumber: 1, NumberOfPages: 1 }, People: [ [Object], [Object], [Object], [Object] ] } ] [ { Pagination: { NumberOfPeople: 185, PageSize: 200, PageNumber: 1, NumberOfPages: 1 }, People: [ [Object], [Object], [Object], [Object] ] } ] // etc etc 30 times
Pagination shouldn’t be returned, and the People objects should return all attributes of the People not in the filteredEmployers list, not the People: [ [Object], [Object], [Object], [Object]
The result I’m after is as follows (or pretty similar):
{ "name": "TJ", "job": "Software Engineer", "organization": { "company": { "employer": "amazon", "department": "IT" } }, "location": { "city": "Boston", "state": "Massachusetts" } }, { "name": "Dominique", "job": "CEO", "organization": { "company": { "employer": "IBM", "department": "IT" } }, "city": "Seattle", "state": "Washington", }
Any advice appreciated. Thanks in advance
Advertisement
Answer
I interpret your question to mean that you want to produce an array of “People” objects, but filter out the ones whose nested “employer” property is a string which includes a substring that is one of the ones in your filter list.
If that’s correct, you can do it this way:
function transform (array, employerFilterList) { const people = array.flatMap(o => o.People); return people.filter(person => { const employer = person?.organization?.company?.employer; // If the person has no employer field, // then the restricted employer filter doesn't apply, // so include the person: if (typeof employer !== 'string') return true; // Else... const employerIsNotFiltered = employerFilterList.every( str => !employer.includes(str) ); return employerIsNotFiltered; }); } const json = `[{"Pagination":{"NumberOfPeople":185,"PageSize":200,"PageNumber":1,"NumberOfPages":1},"People":[{"name":"TJ","job":"Software Engineer","organization":{"company":{"employer":"amazon","department":"IT"}},"location":{"city":"Boston","state":"Massachusetts"}},{"name":"Dominique","job":"CEO","organization":{"company":{"employer":"IBM","department":"IT"}},"city":"Seattle","state":"Washington"},{"name":"Enrique","job":"Engineer","organization":{"company":{"employer":"Bellkrieg Megasystems","department":"Construction"}},"location":{"address":{"state":"New York","city":"New York City","zip":"11323"}}},{"name":"Bob","job":"Project Manager","organization":{"company":{"employer":"Megasystems","department":"R&D"}},"address":{"location":{"quadrant":{"block":1,"state":"Texas","city":"Austin"}}}}]}]`; const data = JSON.parse(json); const filteredEmployers = ['Megasystems', 'Bellkrieg']; const result = transform(data, filteredEmployers); console.log(result); // [{name: "TJ", ...}, {name: "Dominique", ...}]
References: