datatables icon indicating copy to clipboard operation
datatables copied to clipboard

createAdvancedFilter for nested object in nested array with several linked criteria

Open MarLaVay opened this issue 1 year ago • 1 comments

Hello,

First of all, thanks a lot for this great library, it's nice to play with it.

I'm stuck with a specific multi-criteria filter. Here is a sample of what I want to filter :

const contacts = [
    {
        "contactId": "2173",
        "codes": [
            {
                "year": "2010",
                "category": "CIE",
                "group": "CIO"
            },
            {
                "year": "2007",
                "category": "CIE",
                "group": "CIO"
            },
            {
                "year": "2008",
                "category": "PRO",
                "group": "COL"
            }
        ]
    },
    {
        "contactId": "11982",
        "codes": [
            {
                "year": "2017",
                "category": "LIS",
                "group": "FES"
            }
        ]
    },
    {
        "contactId": "12146",
        "codes": [
            {
                "year": "2019",
                "category": "LIS",
                "group": "FES"
            }
        ]
    }
]

I need to filter the contacts by category+group and optionally with a minimum year and a maximum year to add filter by year within each code.

I tried something like this but value cannot be deconstructed:

const filter = handler.createAdvancedFilter( 'codes', (row, value) => {
    const [category, group, minYear, maxYear] = value.split(';')
    if (!minYear && !maxYear) {
      return row.codes?.some((c) => c.category === category && c.group === group)
    } else return row.codes?.some(
      (c) => c.category === category && c.group === group && c.year >= minYear && c.year <= maxYear
    )
  }

and then

filter.set(`${category}-${group}-${minYear}-${maxYear}`)

I cannot create one advanced filter by each category, group and year as I need to filter all these criteria inside each code from the contact's code.

Did I miss something?

I could still change the model, but even if I concat category+group+year, I still have to find year from between 2 dates.

MarLaVay avatar Jul 24 '24 06:07 MarLaVay

Hello, createAdvancedFilter is useful to add a multiple criteria filter when you have values of type string or number. It has limitations for nested objects.

According to your data sample, I would suggest to create 3 different filters instead.

Contacts would be filtered if these 3 criteria are true. For example:

WHERE group IN ('CIO', 'COL')
AND category IN ('CIE', 'LIS')
AND year BETWEEN 2007 AND 2020

Group filter:

type Code = { year: string, category: string, group: string }

const filter = handler.createFilter('codes', (entry: Code[], values: string[]) => {
    const groups = entry.map(item => item.group)
    for(const value of values) {
        if (groups.includes(value)) {
            return true
        }
    }
    return false
})
filter.set(['CIO', 'COL'])

Category filter:

const filter = handler.createFilter('codes', (entry: Code[], values: string[]) => {
    const categories = entry.map(item => item.category)
    for(const value of values) {
        if (categories.includes(value)) {
            return true
        }
    }
    return false
})
filter.set(['CIE', 'LIS'])

Year filter:

const filter = handler.createFilter('codes', (entry: Code[], value: number[]) => {
    // get minYear and maxYear as number[]
    const years = entry.map(item => Number(item.year))
    const [minYear, maxYear] = [Math.min(...years), Math.max(...years)]
    // check
    const [min, max] = value
    return minYear >= min && maxYear <= max
})
filter.set([2007, 2020])

I don't find another way to achieve this.

vincjo avatar Jul 25 '24 12:07 vincjo

Hello, made me think a lot, I didn't find another way neither. Thank you very much vincjo!

MarLaVay avatar Sep 19 '24 10:09 MarLaVay

Hello, thx for your reply. I will probably try this use case with the next version

vincjo avatar Sep 19 '24 14:09 vincjo