I have an array of objects options
similar to:
const options = [
{
"apiName": "tomato",
"category": "veggie",
"color": "red",
"price": "90"
},
{
"apiName": "banana",
"category": "fruit",
"color": "yellow",
"price": "45"
},
{
"apiName": "brinjal",
"category": "veggie",
"color": "violet",
"price": "35"
},
]
I would like to filter this array using a filtering conditions object (generated dynamically) similar to
Example filterGroup 1
let filterGroup = {
type: 'and',
filters: [
{
key: 'category',
condition: 'is',
value: 'veggie'
type: 'filter'
},
{
key: 'price',
condition: 'is less than',
value: '45',
type: 'filter'
}
]
}
Example filterGroup 2
let filterGroup = {
key: 'category',
condition: 'is',
value: 'veggie'
type: 'filter'
}
In the above filterGroup
object each element in the filters array acts as individual filters that each option
in options
should satisfy.
Possible values of condition
are is
, is not
, is less than
and is greater than
.
How can I filter the options
array using the conditions
object in the most efficient way using JavaScript?
What I have tried (REPL Link - https://replit.com/@pcajanand/DarkseagreenEnlightenedTests#index.js),
Made some filter function creators
const eq = (propertyAccessKey, compareValue) => (item) => (item[propertyAccessKey] === compareValue)
const ne = (propertyAccessKey, compareValue) => (item) => (item[propertyAccessKey] === compareValue)
const lt = (propertyAccessKey, compareValue) => (item) => (item[propertyAccessKey] < compareValue)
const gt = (propertyAccessKey, compareValue) => (item) => (item[propertyAccessKey] > compareValue)
Made a function to create filter function with an individual filter (type = filter)
const makeFilterFunction = ({condition, value, key}) => {
if (condition === 'is') {
return (eq(key, value))
} else if (condition === 'is greater than') {
return (gt(key, value))
} else if (condition === 'is less than') {
return (lt(key, value))
} else if (condition === 'is not') {
return (ne(key, value))
}
}
Created filter functions and pushed them into an array,
let fnArray = []
if (filters.type === 'and') {
filters.filters.forEach((filter) => {
fnArray.push(makeFilterFunction(filter))
})
} else if (filters.type === 'filter') {
fnArray.push(makeFilterFunction(filters))
}
Loop through every option, check every filter condition against it, then pushed items passing all conditions to an array as filtered result.
const res = opts.reduce((acc, next) => {
let fnIndex = 0
let fnArrayLength = fnArray.length
let itemPassed = true
while(fnIndex < fnArrayLength) {
const fnPassed = fnArray[fnIndex](next)
if (!fnPassed) {
itemPassed = false
break
}
fnIndex += 1
}
if (itemPassed) {
return acc.concat(next)
} else {
return acc
}
}, [])
While this works (I think?), I want to know if there is some other more efficient way to do this. Or if I'm completely missing something and overcomplicating things.
TLDR - Want to filter an array of objects with multiple chained conditions.
Non-native English speaker here, sorry if the question is ambiguous. Thanks for reading!