'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