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!