How to implement a Search inside a Nested Array of Objects?

Issue

I want to implement a keyword search for a field which is located inside Nested Array of Objects. How can I achieve it?

Data –

const groupList = [{
 "group_name": "General",
 "trainings": [
    {
        "id": 1,
        "training_name": "Plural Sight",
    },
    {
        "id": 2,
        "training_name": "Google Maps",
    }
 ]
}]

Code –

const [groupsData, setGroupsData] = useState([]);

const lowerContains = (str1, str2) => str1 && str2 && str1.toLowerCase().indexOf(str2.toLowerCase()) !== -1;

const handleSearch = searchKeyword => {
    if (searchKeyword && searchKeyword.trim()) {
      const groupFiltered = groupList.filter(item => item.group_name && lowerContains(item.group_name, searchKeyword));
      setGroupsData( groupFiltered );
      return;
    }
    setGroupsData({ [...groupList] });
};

Currently I am able to search with group_name but I want to also search with training_name inside trainings.

Solution

Assuming you want to keep the group object if the searchKeyword is contained within the group name OR one of the training name objects, you can use .some(). By using .some() on trainings, you can check if there is at least one object within the trainings array that contains a training_name value that matches your keyword search:

const groupFiltered = groupList.filter(item => 
  (item.group_name && lowerContains(item.group_name, searchKeyword)) ||
  (item.trainings.some(training => lowerContains(training.training_name, searchKeyword)))
);

Note: In the example data you shared, group_name always contains a value, so you can remove the item.group_name && check if that is always the case.

See working example below:

const groupList = [{ "group_name": "General", "trainings": [{ "id": 1, "training_name": "Plural Sight", }, { "id": 2, "training_name": "Google Maps", } ] }];
const lowerContains = (x, y) => x.toLowerCase().includes(y.toLowerCase());

const searchKeyword = "Plural";
const groupFiltered = groupList.filter(item => 
  (item.group_name && lowerContains(item.group_name, searchKeyword)) ||
  (item.trainings.some(training => lowerContains(training.training_name, searchKeyword)))
);

console.log(groupFiltered);

Answered By – Nick Parsons

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published