How to filter array of JSON-objects with multiple integer conditions and key values

  1. Simplest solution: just hardcode all the fields

let boats = [
  {Price: 599900, BrandName: "FLIPPER", BoatYear: 2020},
  {Price: 97e3  , BrandName: "MICORE" , BoatYear: 2020},
  {Price: 189300, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 396900, BrandName: null     , BoatYear: 2020},
  {Price: 334900, BrandName: "MICORE" , BoatYear: 2019},
  {Price: 138700, BrandName: "HR"     , BoatYear: 2020},
  {Price: 178900, BrandName: "HR"     , BoatYear: 2020},
  {Price: 348900, BrandName: "HR"     , BoatYear: 2020},
  {Price: 285800, BrandName: "HR"     , BoatYear: 2020},
  {Price: 186900, BrandName: "MICORE" , BoatYear: 2019},
  {Price: 276800, BrandName: "MICORE" , BoatYear: 2020},
  {Price: 518900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 226900, BrandName: "MICORE" , BoatYear: 2020},
  {Price: 132600, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 137200, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 366900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 365900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 247900, BrandName: "SILVER" , BoatYear: 2020}
];

const expected_selected = {
  BoatYear : 2020,
  BrandName: 'LINDER',
  Price    : { min: 0, max: 138000 },
}
const filter_by = filters => item => {
  if (item.BoatYear === undefined || item.BoatYear !== filters.BoatYear ) return false
  if (item.BrandName === undefined || item.BrandName !== filters.BrandName ) return false
  if (item.Price < filters.Price.min || item.Price > filters.Price.max) return false
  return true
}
boats = boats.filter(filter_by(expected_selected))

console.log(`Results: ${JSON.stringify(boats)}`);

  1. Or use min/max everywhere

let boats = [
  {Price: 599900, BrandName: "FLIPPER", BoatYear: 2020},
  {Price: 97e3  , BrandName: "MICORE" , BoatYear: 2020},
  {Price: 189300, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 396900, BrandName: null     , BoatYear: 2020},
  {Price: 334900, BrandName: "MICORE" , BoatYear: 2019},
  {Price: 138700, BrandName: "HR"     , BoatYear: 2020},
  {Price: 178900, BrandName: "HR"     , BoatYear: 2020},
  {Price: 348900, BrandName: "HR"     , BoatYear: 2020},
  {Price: 285800, BrandName: "HR"     , BoatYear: 2020},
  {Price: 186900, BrandName: "MICORE" , BoatYear: 2019},
  {Price: 276800, BrandName: "MICORE" , BoatYear: 2020},
  {Price: 518900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 226900, BrandName: "MICORE" , BoatYear: 2020},
  {Price: 132600, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 137200, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 366900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 365900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 247900, BrandName: "SILVER" , BoatYear: 2020},
]

const expected_selected = {
  BoatYear : { min: 2020    , max: 2020     },
  BrandName: { min: 'LINDER', max: 'LINDER' },
  Price    : { min: 0       , max: 138000   },
}
const filter_by = filters => item => {
  for (var key in filters) {
    if (item[key] === undefined) return false
    if (item[key] < filters[key].min || item[key] > filters[key].max) return false
  }
  return true
}
boats = boats.filter(filter_by(expected_selected))

console.log(`Results: ${JSON.stringify(boats)}`);

  1. Or check type of selected field (in this case Array.isArray, in case of {min,max} it would be instanceof)

let boats = [
  {Price: 599900, BrandName: "FLIPPER", BoatYear: 2020},
  {Price: 97e3  , BrandName: "MICORE" , BoatYear: 2020},
  {Price: 189300, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 396900, BrandName: null     , BoatYear: 2020},
  {Price: 334900, BrandName: "MICORE" , BoatYear: 2019},
  {Price: 138700, BrandName: "HR"     , BoatYear: 2020},
  {Price: 178900, BrandName: "HR"     , BoatYear: 2020},
  {Price: 348900, BrandName: "HR"     , BoatYear: 2020},
  {Price: 285800, BrandName: "HR"     , BoatYear: 2020},
  {Price: 186900, BrandName: "MICORE" , BoatYear: 2019},
  {Price: 276800, BrandName: "MICORE" , BoatYear: 2020},
  {Price: 518900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 226900, BrandName: "MICORE" , BoatYear: 2020},
  {Price: 132600, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 137200, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 366900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 365900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 247900, BrandName: "SILVER" , BoatYear: 2020},
]

const expected_selected = {
  BoatYear : 2020,
  BrandName: 'LINDER',
  Price    : [ 0, 138000 ],
}
const filter_by = filters => item => {
  for (var key in filters) {
    if (item[key] === undefined) return false
    if (Array.isArray(filters[key])) {
      if(item[key] < filters[key][0] || item[key] > filters[key][1]) return false
    } else if (item[key] !== filters[key]) return false
  }
  return true
}
boats = boats.filter(filter_by(expected_selected))

console.log(`Results: ${JSON.stringify(boats)}`);

  1. Or better yet, use OOP

let boats = [
  {Price: 599900, BrandName: "FLIPPER", BoatYear: 2020},
  {Price: 97e3  , BrandName: "MICORE" , BoatYear: 2020},
  {Price: 189300, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 396900, BrandName: null     , BoatYear: 2020},
  {Price: 334900, BrandName: "MICORE" , BoatYear: 2019},
  {Price: 138700, BrandName: "HR"     , BoatYear: 2020},
  {Price: 178900, BrandName: "HR"     , BoatYear: 2020},
  {Price: 348900, BrandName: "HR"     , BoatYear: 2020},
  {Price: 285800, BrandName: "HR"     , BoatYear: 2020},
  {Price: 186900, BrandName: "MICORE" , BoatYear: 2019},
  {Price: 276800, BrandName: "MICORE" , BoatYear: 2020},
  {Price: 518900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 226900, BrandName: "MICORE" , BoatYear: 2020},
  {Price: 132600, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 137200, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 366900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 365900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 247900, BrandName: "SILVER" , BoatYear: 2020},
]

class MinMax {
  constructor(min, max) { this.min = min, this.max = max }
  check(val) { return val >= this.min && val <= this.max }
}
class Eq {
  constructor(val) { this.val = val }
  check(val) { return val === this.val }
}
var expected_selected = {
  BoatYear : new Eq(2020),
  BrandName: new Eq('LINDER'),
  Price    : new MinMax(0, 138000)
}
const filter_by = filters => item => {
  for (var key in filters) {
    if (item[key] === undefined) return false
    if (filters[key].check(item[key]) === false) return false
  }
  return true
}
boats = boats.filter(filter_by(expected_selected))

console.log(`Results: ${JSON.stringify(boats)}`);

This way you can extend your filters by adding new classes without changing filter_by function.


Checking objects using key arrays makes sense when we have many properties to validate. In your case you have 4 properties that you need to be check by equality and 3 properties that need to be checked by range, so, if you want to "Don't Repeat Yourself", you can do it using key arrays like in your example and in your project.

You can create a key array for each type you want to check and then validate all these conditions inside a single filter going through all keys. For this example, you'll have an array with keys for the values that need to be checked by equality and one array with keys for values that need to be checked by integer min/max range:

let boats = [
  {Price:599900, BrandName:"FLIPPER", BoatYear:2020},
  {Price:97000, BrandName:"MICORE", BoatYear:2020},
  {Price:189300, BrandName:"LINDER", BoatYear:2020},
  {Price:396900, BrandName:null, BoatYear:2020},
  {Price:334900, BrandName:"MICORE", BoatYear:2019},
  {Price:138700, BrandName:"HR", BoatYear:2020},
  {Price:178900, BrandName:"HR", BoatYear:2020},
  {Price:348900, BrandName:"HR", BoatYear:2020},
  {Price:285800, BrandName:"HR", BoatYear:2020},
  {Price:186900, BrandName:"MICORE", BoatYear:2019},
  {Price:276800, BrandName:"MICORE", BoatYear:2020},
  {Price:518900, BrandName:"SILVER", BoatYear:2020},
  {Price:226900, BrandName:"MICORE", BoatYear:2020},
  {Price:132600, BrandName:"LINDER", BoatYear:2020},
  {Price:137200, BrandName:"LINDER", BoatYear:2020},
  {Price:366900, BrandName:"SILVER", BoatYear:2020},
  {Price:365900, BrandName:"SILVER", BoatYear:2020},
  {Price:247900, BrandName:"SILVER", BoatYear:2020}
];

let expected = {
  BoatYear: 2020,
  BrandName: 'LINDER',
  Price: [0, 138000] // min, max 
}

// Keys that need to be checked by equality
const equals = ['BrandName', 'BoatYear', /* 'MotoBoatType', 'EngineModel' */];

// Keys that need to be checked by range
const ranges = ['Price', /* 'Width', 'Length' */]

boats = boats.filter((item) => {
  // First check the equality keys
  for (const field of equals)
    if (expected[field] && item[field] !== expected[field]) return false;
  
  // Then check the range keys
  for (const field of ranges)
    if (item[field] < expected[field][0] || item[field] > expected[field][1]) return false;

  return true;
});

console.log(`Results: ${boats.length}`, 
  boats.map(({ Price, BrandName, BoatYear }) => `${BrandName} (${BoatYear}) : ${Price}`)
);

You can even make the filter code just 2 lines using Array.prototype.every() to validate the array keys:

let boats = [
  {Price:599900, BrandName:"FLIPPER", BoatYear:2020},
  {Price:97000, BrandName:"MICORE", BoatYear:2020},
  {Price:189300, BrandName:"LINDER", BoatYear:2020},
  {Price:396900, BrandName:null, BoatYear:2020},
  {Price:334900, BrandName:"MICORE", BoatYear:2019},
  {Price:138700, BrandName:"HR", BoatYear:2020},
  {Price:178900, BrandName:"HR", BoatYear:2020},
  {Price:348900, BrandName:"HR", BoatYear:2020},
  {Price:285800, BrandName:"HR", BoatYear:2020},
  {Price:186900, BrandName:"MICORE", BoatYear:2019},
  {Price:276800, BrandName:"MICORE", BoatYear:2020},
  {Price:518900, BrandName:"SILVER", BoatYear:2020},
  {Price:226900, BrandName:"MICORE", BoatYear:2020},
  {Price:132600, BrandName:"LINDER", BoatYear:2020},
  {Price:137200, BrandName:"LINDER", BoatYear:2020},
  {Price:366900, BrandName:"SILVER", BoatYear:2020},
  {Price:365900, BrandName:"SILVER", BoatYear:2020},
  {Price:247900, BrandName:"SILVER", BoatYear:2020}
];

let expected = {
  BoatYear: 2020,
  BrandName: 'LINDER',
  Price: [0, 138000] // min, max 
}

const equals = ['BrandName', 'BoatYear', /* 'MotoBoatType', 'EngineModel' */];
const ranges = ['Price', /* 'Width', 'Length' */]

boats = boats.filter((item) => 
  equals.every(field => !expected[field] || item[field] === expected[field]) &&
  ranges.every(field => item[field] >= expected[field][0] && item[field] <= expected[field][1])
);

console.log(`Results: ${boats.length}`, 
  boats.map(({ Price, BrandName, BoatYear }) => `${BrandName} (${BoatYear}) : ${Price}`)
);

You can check this working on the fork I made from you demo project on Codepen. It has the same method and it applies the validation to all the range keys Price, Width and Length.


You already might have got the solution, but just to put my thought over here I'm posting this answer. I have created a generic function which will take an object(filter object) which can have values with primitives, or object or an array. Hope this helps

let boats = [
  {Price: 599900, BrandName: "FLIPPER", BoatYear: 2020},
  {Price: 97e3  , BrandName: "MICORE" , BoatYear: 2020},
  {Price: 189300, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 396900, BrandName: null     , BoatYear: 2020},
  {Price: 334900, BrandName: "MICORE" , BoatYear: 2019},
  {Price: 138700, BrandName: "HR"     , BoatYear: 2020},
  {Price: 178900, BrandName: "HR"     , BoatYear: 2020},
  {Price: 348900, BrandName: "HR"     , BoatYear: 2020},
  {Price: 285800, BrandName: "HR"     , BoatYear: 2020},
  {Price: 186900, BrandName: "MICORE" , BoatYear: 2019},
  {Price: 276800, BrandName: "MICORE" , BoatYear: 2020},
  {Price: 518900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 226900, BrandName: "MICORE" , BoatYear: 2020},
  {Price: 132600, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 137200, BrandName: "LINDER" , BoatYear: 2020},
  {Price: 366900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 365900, BrandName: "SILVER" , BoatYear: 2020},
  {Price: 247900, BrandName: "SILVER" , BoatYear: 2020}
];

var expected_selected = {
  BoatYear: 2020,
  BrandName: 'LINDER',
  Price: [0, 138000] // min , max 
}

var expected_selected_2 = {
  BoatYear: 2020,
  BrandName: 'LINDER',
  Price: {min:0, max:138000} 
}

var expected_selected_3 = {
  BoatYear: 2020,
  BrandName: 'LINDER',
  Price: 137200
}

const filter_by = (filter) => item => {
for(let key in filter) {
  if(filter.hasOwnProperty(key)){
      if(Array.isArray(filter[key])) {
        if(!item[key] || item[key] < filter[key][0] || item[key] > filter[key][1]) return false;
      }
      else if(typeof filter[key] === "object") {
        if(!item[key] || item[key] < filter[key]["min"] || item[key] > filter[key]["max"]) return false;
      }
      else {
        if(!item[key] || item[key] !== filter[key]) return false;
      }
    } else {
      return false
    }
  }
  return true
}

const results = boats.filter(filter_by(expected_selected))
console.log(`Results: ${JSON.stringify(results, null, 2)}`);

const results_2 = boats.filter(filter_by(expected_selected_2))
console.log(`Results_2: ${JSON.stringify(results_2, null, 2)}`);

const results_3 = boats.filter(filter_by(expected_selected_3))
console.log(`Results_3: ${JSON.stringify(results_3, null, 2)}`);