Reduce data into nested categories



I am trying to reduce an array of data into a nested object. I almost have it except for the next items. Instead of pushing into the array it overwrites the entire array itself leaving only 1 value.

I am 100% sure the issue is with this line of code [...(acc[t.sub_region] || []), t] my gut is telling me I need to do something along the lines of [...(acc[t.region][t.sub_region] || []), t] however it is erroring out when I try this.

I posted a snippet below, as you can see SOUTH_EUROPE only has 1 item inside of its array when it should have 2.

Desired Result

const sorted = {
    EUROPE: {
        SOUTH_EUROPE: [{ item: 'Item 1' }, { item: 'Item 2' }],
        NORTH_EUROPE: [{ item: 'Item 3' }],
    },
    AMERICAS: {
        NORTH_AMERICA: [{ item: 'Item 4' }],
    },
}

const items = [
    {
        region: 'EUROPE',
        sub_region: 'SOUTH_EUROPE',
        item: 'Item 1'
    },
    {
        region: 'EUROPE',
        sub_region: 'SOUTH_EUROPE',
        item: 'Item 2'
    },
    {
        region: 'EUROPE',
        sub_region: 'NORTH_EUROPE',
        item: 'Item 3'
    },
    {
        region: 'AMERICAS',
        sub_region: 'NORTH_AMERCA',
        item: 'Item 4'
    },
]

const sorted = items.reduce((acc, t) => {
    return {
        ...acc,
        [t.region]: {
            ...acc[t.region],
            [t.sub_region]: [...(acc[t.sub_region] || []), t],
        },
    }
}, {})

console.log(sorted)

Answer

sub_region is a nested property, so you need to use acc?.[t.region]?.[t.sub_region] to access it. Note that the optional chaining operator is used to prevent an error from being thrown when the region does not exist yet.

const items = [
    {
        region: 'EUROPE',
        sub_region: 'SOUTH_EUROPE',
        item: 'Item 1'
    },
    {
        region: 'EUROPE',
        sub_region: 'SOUTH_EUROPE',
        item: 'Item 2'
    },
    {
        region: 'EUROPE',
        sub_region: 'NORTH_EUROPE',
        item: 'Item 3'
    },
    {
        region: 'AMERICAS',
        sub_region: 'NORTH_AMERCA',
        item: 'Item 4'
    },
]

const sorted = items.reduce((acc, t) => {
    return {
        ...acc,
        [t.region]: {
            ...acc[t.region],
            [t.sub_region]: [...(acc?.[t.region]?.[t.sub_region] || []),
                              {item: t.item}],
        },
    }
}, {})

console.log(sorted)


Source: stackoverflow