'How to filter an object array if the value of an object match array [duplicate]

I have the following object table :

 let data = [
   {key:"20-09-2019", skill: [{id: 500, message: "monday"}, {id: 501, message: "tuesday"}]},
   {key:"21-09-2019", skill: [{id: 502, message: "thursday"}, {id: 503, message: "sunday"}]},
   {key:"22-09-2019", skill: [{id: 504, message: "sunday"}]},
]

let search = "sun"

I would like to filter the table if the value of "message" match with the value of "search"

if search = "sun" the filter should return the following result:

result after filter :

 data = [
   {key:"21-09-2019", skill: [ {id: 503, message: "sunday"}]},
   {key:"22-09-2019", skill: [{id: 504, message: "sunday"}]},
]

here the array only returns the objects having the message value that match with "sun"

I know the filter method but I do not think we can do a filter in a filter.

I also know the method that allows me to match the message :

 message.toLowerCase().includes(search);

but I do not know how to filter the object array, if anyone has an idea?



Solution 1:[1]

You can filter on skill field of each element by search value first then filter elements that still have skill.

let search = "sun";
let data = [
   {key:"20-09-2019", skill: [{id: 500, message: "monday"}, {id: 501, message: "tuesday"}]},
   {key:"21-09-2019", skill: [{id: 502, message: "thursday"}, {id: 503, message: "sunday"}]},
   {key:"22-09-2019", skill: [{id: 504, message: "sunday"}]},
];
data.forEach(el => {
  el.skill = el.skill.filter(s => s.message.toLowerCase().includes(search))
});
let result = data.filter(el => el.skill.length);
console.log(result)

Edit for not mutate the original array:

let search = "sun";
let data = [
  {key:"20-09-2019", skill: [{id: 500, message: "monday"}, {id: 501, message: "tuesday"}]},
  {key:"21-09-2019", skill: [{id: 502, message: "thursday"}, {id: 503, message: "sunday"}]},
  {key:"22-09-2019", skill: [{id: 504, message: "sunday"}]},
    ];
let result = data.reduce((acc, {skill, ...rest}) => {
   skill = skill.filter(s => s.message.toLowerCase().includes(search));
   if(skill.length) acc.push({skill, ...rest});
   return acc;
}, []);
console.log(result);

Solution 2:[2]

I do not think we can do a filter in a filter.

Yes you can but I would use forEach(). Example below.

let data = [
   {key:"20-09-2019", skill: [{id: 500, message: "monday"}, {id: 501, message: "tuesday"}]},
   {key:"21-09-2019", skill: [{id: 502, message: "thursday"}, {id: 503, message: "sunday"}]},
   {key:"22-09-2019", skill: [{id: 504, message: "sunday"}]},
]

let search = 'sunday';
let result = [];

data.forEach(row=>{
  let found = row.skill.filter((skill=>skill.message === search));
  if (found.length) result.push({key:row.key,skill:found});
})

console.log(result);

Solution 3:[3]

You can do it this way

let data = [
   {key:"20-09-2019", skill: [{id: 500, message: "monday"}, {id: 501, message: "tuesday"}]},
   {key:"21-09-2019", skill: [{id: 502, message: "thursday"}, {id: 503, message: "sunday"}]},
   {key:"22-09-2019", skill: [{id: 504, message: "sunday"}]},
];

let search = "sun"

const newItems = data.filter(item => item.skill.filter(sk => sk.message.includes(search)).length);
newItems.forEach(item => {
  item.skill = item.skill.filter(x => x.message.includes(search))
})

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3