'Filter multiple Array Objects and match key values with multiple values form another array in Javascript
Been racking my head for a few nights now and Im hoping a kind soul can help solve this wall I have hit.
I have an Array of Objects.
As a user I should be able to filter feature name(s) by multiple or singular filters. A single filter should return all events with a matching name A multiple filter should match all events with more than one feature name, not less than 2 or the length of the filters array.
The code I have eventually been stuck with or as far as I can go is this.
let obj1 = [{
"results": [{
"id": "1",
"name": "Event 1",
"feature": [{
"id": {
"target": "78"
},
"name": "Bronze"
},
{
"id": {
"target": "27"
},
"name": "Straw"
},
{
"id": {
"target": "45"
},
"name": "Gold"
}
]
},
{
"id": "2",
"name": "Event 2",
"feature": [{
"id": {
"target": "20"
},
"name": "Straw"
}]
},
{
"id": "3",
"name": "Event 3",
"feature": [{
"id": {
"target": "20"
},
"name": "Gold"
},
{
"id": {
"target": "20"
},
"name": "Straw"
}
]
},
{
"id": "4",
"name": "Event 4",
"feature": [{
"id": {
"target": "97"
},
"name": "Coal"
},
{
"id": {
"target": "39"
},
"name": "Wood"
}
]
}
]
}]
let filterQuery = ['Straw', 'Gold'];
obj1 = obj1[0].results.filter(r => {
return r.feature.every(f => {
return filterQuery.includes(f.name)
})
})
console.log(obj1);
It filters anything with Straw or Gold, and everything with Straw and Gold
Im trying to get the filter to filter Straw && Gold
So returning an event(s) with example
{name: 'Straw', name: 'Gold', name: 'Diamond', name: Copper}
would be a correct match, so a user could add another filter to the array to filter the results further.
{ name: Straw, name: Diamond }
Would not be a correct match.
Any help, suggestions would be greatly appreciated :)
===========================================================
Updated, solved solution. I needed it to be agnostic as possible so it works if key names change. Used in a Vuejs project with Drupal.
export default class FilterData {
constructor(name, data, filter_query) {
this.name = name;
this.data = data;
this.filter_query = filter_query;
}
filterData(){
let temp = this.data
// filter out any undefined arrays
temp = temp.filter((item) => item[this.name] !== undefined);
temp = temp.filter((item) =>
[this.filter_query].every((filter) =>
item[this.name].some(({ name }) => name === filter)
)
);
return temp
}
}
And use it like so
/* use a temp copy of the returned data from the api
so we can keep refiltering from multiple drop downs, radio, checkboxes changes each time a filter keyname is un-selected.
*/
let apiResults = this.apiData.results;
let filtered = new FilterData(
`${keyname}`,
apiResults,
this.filterQuery[`${keyname}`]
);
Thank you so much @pilchard your answer helped this greatly.
Solution 1:[1]
You need to switch your every() call to the filterQuery array. So test if every() string in the filter array has a match in the feature array, here testing with some().
let obj1 = [{ "results": [{ "id": "1", "name": "Event 1", "feature": [{ "id": { "target": "78" }, "name": "Bronze" }, { "id": { "target": "27" }, "name": "Straw" }, { "id": { "target": "45" }, "name": "Gold" }] }, { "id": "2", "name": "Event 2", "feature": [{ "id": { "target": "20" }, "name": "Straw" }] }, { "id": "3", "name": "Event 3", "feature": [{ "id": { "target": "20" }, "name": "Gold" }, { "id": { "target": "20" }, "name": "Straw" }] }, { "id": "4", "name": "Event 4", "feature": [{ "id": { "target": "97" }, "name": "Coal" }, { "id": { "target": "39" }, "name": "Wood" }] }] }]
let filterQuery = ['Straw', 'Gold'];
const filteredObj = obj1[0].results.filter(({ feature }) =>
filterQuery.every(filter =>
feature.some(({ name }) => name === filter)))
console.log(filteredObj);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
