Digress
Digress

Reputation: 53

Can I filter an array of objects in javascript with a substring?

I am attempting to filter an array of objects using multiple different filters. This currently works for an exact match but doesn't work for filtering using a substring. Is there a way to simply modify this filter function to to return all values that have a partial match?

nestedFilter(data, filters) {

  let filterKeys = Object.keys(filters);
  return data.filter(function (eachObj) {
    return filterKeys.every(function (eachKey) {
      if (!filters[eachKey].length) {
        return true;
      }
      return filters[eachKey].includes(eachObj[eachKey]);
    });
  });
}

So using the below data and filters:

data = [
    {
        "NAME": "Johnathon", 
        "AGE": "19 ",
        "GENDER": "M",
        "SPORT": "Hockey",
        "SCHOLARSHIP": "N"
    },
    {
        "NAME": "Jessica", 
        "AGE": "20",
        "GENDER": "F",
        "SPORT": "Football",
        "SCHOLARSHIP": "Y"
    },
    {
       "NAME": "Matty", 
       "AGE": "20",
       "GENDER": "NB",
       "SPORT": "Tennis",
       "SCHOLARSHIP": "Y"
   },
   {
      "NAME": "Amy", 
      "AGE": "20",
      "GENDER": "F",
      "SPORT": "Football",
      "SCHOLARSHIP": "N"
   }
]

filters = [
   {
      "NAME": [],
      "AGE": [],
      "GENDER": [],
      "SPORT": ["Foot", "Hockey"],
      "SCHOLARSHIP": []
   }
]

It should return Johnathon, Jessica and Amy objects.

(Filters in different fields act as AND and filters in the same field act as OR).

Upvotes: 4

Views: 2183

Answers (2)

Vignesh Raja
Vignesh Raja

Reputation: 8761

Using Array.reduce(), AND can be implemented in every iteration

Using Array.some(), OR can be implemented for each filter

Filter only if the array is not empty.

var data = [
    { "NAME": "Johnathon", "AGE": "19 ", "GENDER": "M", "SPORT": "Hockey", "SCHOLARSHIP": "N" },
    { "NAME": "Jessica", "AGE": "20", "GENDER": "F", "SPORT": "Football", "SCHOLARSHIP": "Y" },
    { "NAME": "Matty", "AGE": "20", "GENDER": "NB", "SPORT": "Tennis", "SCHOLARSHIP": "Y" },
    { "NAME": "Amy", "AGE": "20", "GENDER": "F", "SPORT": "Football", "SCHOLARSHIP": "N" }
];

var filters = {
      "NAME": ["Amy"],
      "AGE": [],
      "GENDER": [],
      "SPORT": ["Foot", "Hockey"],
      "SCHOLARSHIP": ["Y","N"]
   };
   
var filterkeys = Object.keys(filters);
var result = data.slice(0);
filterkeys.forEach(function(filterkey){
    if(filters[filterkey].length)
    {
        result = result.reduce(function(acc, value){
            filters[filterkey].some(function(filtervalue){
                return value[filterkey].indexOf(filtervalue)>-1;
            }) && acc.push(value);
            return acc;
        },[]);
    }
});

console.log(result)

Upvotes: 0

gnerkus
gnerkus

Reputation: 12019

To employ a partial match for the object's property, you would want to check if the value contains at least one of the items in the list of filters. For example:

"Footbal".includes("Foot") || "Football".includes("Hockey") // true;

We can use Array.some to make this assertion:

return filters[eachKey].some(key => {
  return eachObj[eachKey].includes(key);
});

A little correction:

The filters variable is an array so you might want to either convert it to an object or run the nestedFilter function with filters[0] (referring to the first item in the array)

Upvotes: 1

Related Questions