I’m trying to filter an array of objects based on the objects found into another array.
Basically, I need to filter a list based on some filters selected by the user.
Assuming my list of results is something like this:
[
{uuid: 1, type: 2, style: 3, somethingelse: 4, anotherval: 5}
{uuid: 2, type: 4, style: 4, somethingelse: 4, anotherval: 5}
{uuid: 3, type: 6, style: 4, somethingelse: 4, anotherval: 5}
{uuid: 4, type: 9, style: 2, somethingelse: 4, anotherval: 5}
{uuid: 5, type: 1, style: 2, somethingelse: 4, anotherval: 5}
....
]
and the list I need to use as a filter list is a dynamic list ( I don’t know which values or keys will be present in this list since it is selected by the user on the ui)
that might look like this:
[
{key: 'type', value: '2'},
{key: 'style', value: '4'}
]
what I am trying to achieve is a filtered list that returns only the values that have both the key-value pair above true
I have checked many answers here on stack overflow, just to mention a few:
How to check if a value exists in an object using JavaScript
How to efficiently check if a Key Value pair exists in a Javascript "dictionary" object
lodash: filter array of objects with a different array of objects
Filtering for Multiple Fields in Object Array in Javascript/Lodash – Stack Overflow
and many more, but with no luck.
What I currently have is something that looks like this:
...
//Here I am transforming the filters into the array with format {key: '', value: ''}
// that I was mentioning before. This is not mandatory, If you recon it is not needed
// I can easily remove this. The default format for my filters before converting them
// to array looks like this {type: 2, style: 4}
const filterArr = Object.keys(cleanedFilters).map(key => ({ key, value: cleanedFilters[key] }))
const result = flatten(
map(filterArr, function (fil) {
return filter(searchResults, function (a) {
return a.hasOwnProperty(fil.key) && a[fil.key] === parseInt(fil.value)
})
})
)
the result of this snipper is an array that looks like this:
[
{
"uuid": 1,
"type": 2,
"style": 3,
"somethingelse": "4",
"anotherval": 5
},
{
"uuid": 2,
"type": 4,
"style": 4,
"somethingelse": "4",
"anotherval": 5
},
{
"uuid": 3,
"type": 6,
"style": 4,
"somethingelse": "4",
"anotherval": 5
}
]
which is basically appending everything that has both style = 4
and type = 2
My desired result is a list with only the objects that match all the filters (which, in this case, should have been an empty array since I don’t have an entry with style 4 and type 2
As you can see from the example snipper I don’t mind using lodash if needed.
Thanks in advance for any possible suggestions you might have to provide
3
Answers
Just filter the array with all items in the filter matching.
The only problem that your filter contains string values but the array does number ones. So there’re several ways to compare, just choose the most appropriate for you.
As you mentioned your filter is initially an object, so this could be done like this also:
If you want the best performance (for example in case of filtering a big array from the backend) you could generate a filter function:
And the benchmark:
As you iterate over the object in the data array use
every
to check that every object key/value in the query passes the condition that it exists in the current iterated object.If you expect valid integers as the values, you’ll need to validate that user input (in the
parseFilter
function below). Beyond that, to filter according to the intersection of every filter value (booleanAND
), you can useArray.prototype.every()
:TS Playground
Compiled JS: