0

I need to filter a nested array based on an array of string values like so:

const filters = ["Berlin", "Paris"]

This is the base array that needs to be filtered (need to filter the jobs array based on location key)

const departments = [
  {
    name: "Brand",
    children: [
      {
        name: "Marketing",
        jobs: [
          { location: "Paris", title: "Brand Manager" },
          { location: "Berlin", title: "Brand Designer" },
          { location: "New York", title: "Brand Designer" }
        ],
      },
    ],
  },
  {
    name: "Business",
    children: [
      {
        name: "People",
        jobs: [
          { location: "Paris", title: "Office Manager" },
          { location: "Berlin", title: "Office Manager" },
          { location: "New York", title: "Office Manager" }
        ],
      },
    ],
  },
];

Expected output would be:

const filteredDepartments = [
  {
    name: "Brand",
    children: [
      {
        name: "Marketing",
        jobs: [
          { location: "Paris", title: "Brand Manager" },
          { location: "Berlin", title: "Brand Designer" }
        ],
      },
    ],
  },
  {
    name: "Business",
    children: [
      {
        name: "People",
        jobs: [
          { location: "Paris", title: "Office Manager" },
          { location: "Berlin", title: "Office Manager" }
        ],
      },
    ],
  },
];

Any help/pointers would be appreciated as I'm hitting a deadend, thanks!

  • 3
    What have you tried so far? Can you share your code? – Tasos Oct 08 '20 at 16:21
  • 1
    Does this answer your question? [Filter array of objects whose any properties contains a value](https://stackoverflow.com/questions/44312924/filter-array-of-objects-whose-any-properties-contains-a-value) – Akif Oct 08 '20 at 16:28
  • 1
    please add the wanted result. what happens, if `jobs` is empty? do you want to exclude the next levels as well? – Nina Scholz Oct 08 '20 at 16:31

4 Answers4

1

Something like this? It's a bit straight forward but, it works for that structure and only 2 levels deep. if you need to work for n levels, recursivity is needed.

const filters = ["Berlin", "Paris"];

const departments = [
  {
    name: "Brand",
    children: [
      {
        name: "Marketing",
        jobs: [
          { location: "Paris", title: "Brand Manager" },
          { location: "Berlin", title: "Brand Designer" },
          { location: "New York", title: "Brand Designer" }
        ],
      },
    ],
  },
  {
    name: "Business",
    children: [
      {
        name: "People",
        jobs: [
          { location: "Paris", title: "Office Manager" },
          { location: "Berlin", title: "Office Manager" },
          { location: "New York", title: "Office Manager" }
        ],
      },
    ],
  },
];

const filteredDepartments = departments.map(department => {
  department.children = department.children.map(child => {
    child.jobs = child.jobs.filter(job => filters.includes(job.location));
    
    return child;
  });
  
  return department;
});

console.log(filteredDepartments);
1

Please try this code snippet. This code will not mutates the original array.

const filters = ["Berlin", "Paris"]
const departments = [
  {
name: "Brand",
children: [
  {
    name: "Marketing",
    jobs: [
      { location: "Paris", title: "Brand Manager" },
      { location: "Berlin", title: "Brand Designer" },
      { location: "New York", title: "Brand Designer" }
    ],
  },
],
  },
  {
name: "Business",
children: [
  {
    name: "People",
    jobs: [
      { location: "Paris", title: "Office Manager" },
      { location: "Berlin", title: "Office Manager" },
      { location: "New York", title: "Office Manager" }
    ],
  },
],
  },
];


const filteredDepartments = departments.map(department => {
  let children = [];
  children = department.children.map(child => {
let jobs = [...child.jobs];
jobs = jobs.filter(job => filters.includes(job.location));
return {
  name: child.name,
  jobs
};
  });
  return {
name: department.name,
children
  };
});
console.log(filteredDepartments);
Pulkit Aggarwal
  • 2,554
  • 4
  • 23
  • 33
1

   const filters = ["Berlin", "Paris"];

const departments = [
  {
name: "Brand",
children: [
  {
    name: "Marketing",
    jobs: [
      { location: "Paris", title: "Brand Manager" },
      { location: "Berlin", title: "Brand Designer" },
      { location: "New York", title: "Brand Designer" }
    ],
  },
],
  },
  {
name: "Business",
children: [
  {
    name: "People",
    jobs: [
      { location: "Paris", title: "Office Manager" },
      { location: "Berlin", title: "Office Manager" },
      { location: "New York", title: "Office Manager" }
    ],
  },
],
  },
];

const filteredDepartments = departments.map(({name, children}) => {
  const filteredChildren = children.map(({name, jobs}) => {
  const newJobs = jobs.filter(job => filters.includes(job.location));

    return {name, jobs: newJobs};
  });
  
  return {name, children: filteredChildren};
});
console.log('filteredDepartments => ', filteredDepartments);
console.log('departments =>', departments);
Sarun UK
  • 6,210
  • 7
  • 23
  • 48
1

This answer removes a child from the children array if there are no matching jobs and also removes a department from the departments array if there are no children left.

const departments = [
  {
    name: "Brand",
    children: [
      {
        name: "Marketing",
        jobs: [
          { location: "Paris", title: "Brand Manager" },
          { location: "Berlin", title: "Brand Designer" },
          { location: "New York", title: "Brand Designer" }
        ],
      },
    ],
  },
  {
    name: "Business",
    children: [
      {
        name: "People",
        jobs: [
          { location: "Paris", title: "Office Manager" },
          { location: "Berlin", title: "Office Manager" },
          { location: "New York", title: "Office Manager" }
        ],
      },
    ],
  },
];

const filters = ["Berlin", "Paris"];

const filteredDepartments = [];
for (const department of departments) {
  const children = [];
  for (const child of department.children) {
    const jobs = child.jobs.filter(({location}) => filters.includes(location));
    if (jobs.length) children.push({...child, jobs});
  }
  if (children.length) filteredDepartments.push({...department, children});
}

console.log("departments", departments);
console.log("filteredDepartments", filteredDepartments);

This answer makes use of object destructuring and the object spread syntax. Have a look at the linked documentation if you don't know what these are.

3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
  • Thanks that helps a lot :) I indeed have to remove the department if there is no job, but I'm sure I can figure something out! –  Oct 08 '20 at 17:15
  • @KoppiMeister I've updated the answer. It's now a less functional approach, but removes a child from the array if it has no jobs left and removes a department from the array if there are no children left. – 3limin4t0r Oct 08 '20 at 20:08
  • @3limin4t0r Can you explain if (jobs.length)? Does it check if there are any jobs? – MikiBelavista Oct 09 '20 at 04:41
  • 1
    @MikiBelavista Yes, it is the same as `if (jobs.length != 0)`. `0` is a falsey value, thus the object will only be pushed in the array if the length is not `0`. If you find the statement confusing you could write `if (jobs.length > 0)` to be more explicit. – 3limin4t0r Oct 09 '20 at 08:41