Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Chaining Filters within a Loop

I currently have a collection of data called venues that contain the following fields:

const venues = [
{
name: 'test1',
categories: ['1a', '1b'],
currencies: ['2a', '2b']

},
{
name: 'test2',
categories: ['1b'],
currencies: ['2a']

}
]

The categories/currencies fields within each venue object contain the ids of the category they belong to and the currencies they accept.

I then have an array of filters that looks like the following:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

const filters = [
{
name: 'art',
id: '1a',
type: 'categories'
},
{
name: 'testCurrency',
id: '2b',
type: 'currencies'
},
]

In order to chain the filters for currencies and categories I am doing the following:

 const filterVenueData = (venues, filterByType, key) => {
    const filteredVenues = venues.filter((venue) => {
      if (!filterByType[key]?.length) return true
      return filterByType[key].some((filters) => {
        return venue[key].includes(filters.id)
      })
    })

    return filteredVenues
  }



  const filtersByType = filters.reduce(
        (hash, obj) => ({
          ...hash,
          [obj['type']]: (hash[obj['type']] || []).concat(obj)
        }),
        {}
      )

const filterByCategory = filterVenueData(
        venues,
        filtersByType,
        'categories'
      )
      const filterByCurrency = filterVenueData(
        filterByCategory,
        filtersByType,
        'currencies'
      )

console.log(filterByCurrency)

while this works… I can’t help but feel like having to call the function twice (and pass in the key to filter by) in order to chain the filters for both currency and categories seems very inefficient. Is there a way to chain the filters using a loop as opposed to having to call the function twice/pass in what key to filter by? I would like the filters to be strict, meaning in this current example, only venues who belong to the art category and accept testCurrency should appear (test1 venue).

I have attached a code sandbox for debugging: https://codesandbox.io/s/serverless-rain-dmluz?file=/src/index.js

>Solution :

Instead of using filterVenueData for each type of filter, use the filtersByType object and iterate over its entries – check that .every one of its entries passes the test (that is, that the venue contains one of the IDs).

const venues=[{name:"test1",categories:["1a","1b"],currencies:["2a","2b"]},{name:"test2",categories:["1b"],currencies:["2a"]}],filters=[{name:"art",id:"1a",type:"categories"},{name:"testCurrency",id:"2b",type:"currencies"}];

const filtersByType = {};
for (const { id, type } of filters) {
  filtersByType[type] ??= [];
  filtersByType[type].push(id);
}
const output = venues.filter(obj =>
  Object.entries(filtersByType).every(([key, arr]) =>
    arr.some(id => obj[key].includes(id))
  )
);
console.log(output);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading