Skip to content
Advertisement

Filter array of objects with available or not filters

Suppose I have this dataset:

const data = [ 
  {animal: 'cat', name: 'mu', year: 2016},
  {animal: 'cat', name: 'muji', year: 2021},
  {animal: 'cat', name: 'mine', year: 2021},
  {animal: 'dog', name: 'fido', year: 2000}, 
  {animal: 'hamster', name: 'gerry', year: 2020}, 
  {animal: 't-rex', name: 'dino', year: 2020}, 
  {animal: 'sheep', name: 's', year: 2019}, 
  {animal: 'sheep', name: 'sss', year: 2016}, 
]

and I want to filter it by some values, for example by animal and by year. Very easy I can do:

const animal = 'sheep'
const year = 2019

const filteredData = data.filter(d => d.animal === animal && d.year === year)
// result
const filteredData = [ 
  {animal: 'sheep', name: 's', year: 2019}, 
]

same here:

const animal = 'cat'
const year = 2021
const filteredData = [ 
  {animal: 'cat', name: 'muji', year: 2021},
  {animal: 'cat', name: 'mine', year: 2021},
]

My problem is that sometimes animal or year can be null. In that case I want not to filter by that value. For example these are what I would like to obtain:

const animal = 'cat'
const year = null
const filteredData = [ 
  {animal: 'cat', name: 'mu', year: 2016},
  {animal: 'cat', name: 'muji', year: 2021},
  {animal: 'cat', name: 'mine', year: 2021},
]

// ---

const animal = null
const year = 2020
const filteredData = [ 
  {animal: 'hamster', name: 'gerry', year: 2020}, 
  {animal: 't-rex', name: 'dino', year: 2020},
]

// ---

const animal = null
const year = null
const filteredData = [ 
  {animal: 'cat', name: 'mu', year: 2016},
  {animal: 'cat', name: 'muji', year: 2021},
  {animal: 'cat', name: 'mine', year: 2021},
  {animal: 'dog', name: 'fido', year: 2000}, 
  {animal: 'hamster', name: 'gerry', year: 2020}, 
  {animal: 't-rex', name: 'dino', year: 2020}, 
  {animal: 'sheep', name: 's', year: 2019}, 
  {animal: 'sheep', name: 'sss', year: 2016}, 
]

How can I do that?

Note that this is only a simple example, in my case I could have more than two variables as filters.

Advertisement

Answer

As you have written “I could have more than two variables as filters…“, I don’t think it is a good idea to hard-code filter expressions. Moreover, if both your data and filter are dynamic (if properties are not known beforehand) it is not even possible. Instead, you can use some approach like this:

const data = [
  { animal: 'cat', name: 'mu', year: 2016 },
  { animal: 'cat', name: 'muji', year: 2021 },
  { animal: 'cat', name: 'mine', year: 2021 },
  { animal: 'dog', name: 'fido', year: 2000 },
  { animal: 'hamster', name: 'gerry', year: 2020 },
  { animal: 't-rex', name: 'dino', year: 2020 },
  { animal: 'sheep', name: 's', year: 2019 },
  { animal: 'sheep', name: 'sss', year: 2016 }
];

const query = { animal: 'cat', year: null };

// remove all null values
// https://stackoverflow.com/a/38340730
const q = Object.fromEntries(Object.entries(query).filter(([_, v]) => v != null));

// https://stackoverflow.com/a/61676007
const isSubset = (superObj, subObj) => {
  return Object.keys(subObj).every(ele => {
    if (typeof subObj[ele] == 'object') return isSubset(superObj[ele], subObj[ele]);
    return subObj[ele] === superObj[ele];
  });
};

const filteredData = data.filter(d => isSubset(d, q));

console.log(filteredData);
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement