Home > Mobile >  Filtering an object Array on multiple columns. using AND if its a diffrent column, OR if its the sam
Filtering an object Array on multiple columns. using AND if its a diffrent column, OR if its the sam

Time:06-09

I have a giant list of entries with thousands of elements, i have created a list of checkbox filters for each column thats a unique list of each value in that column. I now want to filter the list based on what the checkboxes the user clicks in the app. The list looks something like this

[{ 
  Value1: "val", 
  Value2: "more value", 
  Value3: "1"
},{ 
  Value1: "val1", 
  Value2: "test", 
  Value3: "1" 
},{ 
  Value1: "val1", 
  Value2: "test", 
  Value3: "2" 
},{ 
  Value1: "val", 
  Value2: "test", 
  Value3: "3" 
}];

So the filters woul look something like this.

Value1

  • val
  • val1

value2

  • test

value 3

  • 1
  • 2
  • 3

if a user checks 3 in the value 3 boxes i just wanna show the objects with value3 = 3, if they check 2 in the value 3 boxes i wanna show value 3 = 3 OR value 3 = 2. if they check val1 in value 1 boxes i wanna show objects where Value 3 = 3 OR 2 AND value 1 = val1. meaning i would only show the 3rd element in the array because it meets all 3 conditions.

How can i achieve this using Typescript/Javascript. All filterable values are strings

currently im trying something like this, but that just shows everything that has one value matching.

let newFilterObj = [{ fieldName: "value3", value: "3" }, { fieldName: "value3", value: "2" }, { fieldName: "value1", value: "val1" }]

let newList = ListAllItems.filter((i) => {
    const found = newFilterObj.some(element => {
        return i[element.fieldName] === element.value;
    });
    return found;
});

CodePudding user response:

you can do something like this

basically you group all your filters by key

than you use every for the AND condition

and include fro the OR condition

const applyFilters = (data, filter) => {
    const groupFilter = Object.values(filter.reduce((res, {fieldName, value}) => {
        const existingFilter = res[fieldName] || {fieldName, values:[]}
        return {
            ...res,
            [fieldName]: {
                ...existingFilter,
                values: [...existingFilter.values, value]
            }
        }
    }, {}))
 
    return data.filter(d => groupFilter.every(f => f.values.includes(d[f.fieldName])))

}


const ListAllItems = [{
    Value1: "val",
    Value2: "more value",
    Value3: "1"
},{
    Value1: "val1",
    Value2: "test",
    Value3: "1"
},{
    Value1: "val1",
    Value2: "test",
    Value3: "2"
},{
    Value1: "val",
    Value2: "test",
    Value3: "3"
}];

let newFilterObj = [{ fieldName: "Value3", value: "3" }, { fieldName: "Value3", value: "2" }, { fieldName: "Value1", value: "val1" }]



console.log(applyFilters(ListAllItems, newFilterObj))

CodePudding user response:

You should collect all available filter values and than check

const ListAllItems = [{
    value1: 'val',
    value2: 'more value',
    value3: '1',
}, {
    value1: 'val1',
    value2: 'test',
    value3: '1',
}, {
    value1: 'val1',
    value2: 'test',
    value3: '2',
}, {
    value1: 'val',
    value2: 'test',
    value3: '3',
},
]

let newFilterObj = [{ fieldName: 'value3', value: '3' }, { fieldName: 'value3', value: '2' }, {
    fieldName: 'value1',
    value: 'val1',
},
]

const filedValues = {}

newFilterObj.forEach(({ fieldName, value }) => {
    if (filedValues[fieldName]) {
        filedValues[fieldName].push(value)
    } else {
        filedValues[fieldName] = [value]
    }
})

console.log(filedValues)
/*
 {
     "value3": [
         "3",
         "2"
     ],
     "value1": [
         "val1"
     ]
 }
 */

let newList = ListAllItems.filter((i) => {
    for ([key, value] of Object.entries(filedValues)) {
        if (!value.includes(i[key])) {
            return false
        }
    }
    return true
})

console.log('newList', newList)
/*
 [
     {
     "value1": "val1",
     "value2": "test",
     "value3": "2"
     }
 ]
 */
  • Related