Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filter by multiple keys and values, Javascript

I'm trying to make a filter. The number of filters will change dynamically, a number of keys can be different, and the number of values, too.

This is how data look like:

var data = [
{id: "123", color: "Red", model: "Tesla"}, 
{id: "124", color: "Black", model: "Honda"}, 
{id: "125", color: "Red", model: "Audi"}, 
{id: "126", color: "Blue", model: "Tesla"}]

Filter keys are color and model. But sometimes I will filter only by color or model and sometimes by both. I want to make a function that will cover both cases. Also, a user can choose many values (Tesla, Honda...).

Key can be only color, or only model, or both. Values can look like: only "Red", "Red" and "Blue", or "Red" and "Tesla", or "Red", "Blue" and "Tesla"... Depends on what user choose.

I tried this:

var filtered = [];
data.forEach(item => {
   filterByKey.forEach(key => {
      values.forEach(value => {
         if (item[key] === value) {
             filtered.push(item);
          }
       });
    });
  });

Here is JsFiddle

My loop works well when I have one filter key, but it doesn't work well when I have more than one key. Is it a good idea to pass keys and values as an array?

No jQuery please, only pure JavaScript.

like image 709
snoopy25 Avatar asked Jun 16 '17 13:06

snoopy25


2 Answers

You can use filter() with every() and check if value of current object with current key exits in values array using includes()

var data = [{"id":"123","color":"Red","model":"Tesla"},{"id":"124","color":"Black","model":"Honda"},{"id":"125","color":"Red","model":"Audi"},{"id":"126","color":"Blue","model":"Tesla"}]

var keys = ["color", 'model'];
var values = ["Tesla", "Audi", "Red"];

var result = data.filter(function(e) {
  return keys.every(function(a) {
    return values.includes(e[a])
  })
})

console.log(result);
like image 170
Nenad Vracar Avatar answered Sep 22 '22 00:09

Nenad Vracar


You could use a combined approach with a seach object which keeps the conditions, like

{ 
    model: 'Tesla',                                    // a single value
    color: ['red', 'blue'],                            // a some value
    price: {                                           // a range/interval
        min: 2000, 
        max: 3000
    },
    transmission: v => v.toLowerCase() === 'automatic' // a function
}

var useConditions = search => a => Object.keys(search).every(k => 
        a[k] === search[k] ||
        Array.isArray(search[k]) && search[k].includes(a[k]) ||
        typeof search[k] === 'object' && +search[k].min <= a[k] &&  a[k] <= +search[k].max ||
        typeof search[k] === 'function' && search[k](a[k])
    ),
    data = [{ id: "123", color: "Red", model: "Tesla" }, { id: "124", color: "Black", model: "Honda" }, { id: "125", color: "Red", model: "Audi" }, { id: "126", color: "Blue", model: "Tesla" }],
    filters = { color: ['Red', 'Blue'], model: 'Tesla' };

console.log(data.filter(useConditions(filters)));
like image 37
Nina Scholz Avatar answered Sep 20 '22 00:09

Nina Scholz