Search code examples
angularreactjsreduxngrxdatabase-normalization

How to normalize deep nested data in the ngrx/store?


I am using ngrx/store and Angular 6. I have deep nested structure in the store. But i feel like it is not correct way to keep it like this:

const state = [
  {
    aliases: ['alias1', 'alias2'],
    isRequired: false,
    isSensitive: false,
    name: 'Adress',
    timezoneId: 'UTC',
    children: []
  },
  {
    aliases: ['alias3', 'alias4'],
    isRequired: true,
    isSensitive: false,
    name: 'Phone',
    timezoneId: 'UTC-5',
    children: [
      {
        aliases: ['alias1', 'alias2'],
        isRequired: true,
        isSensitive: false,
        name: 'Sub-Phone',
        timezoneId: 'UTC-5',
        children: [
          {
            aliases: ['alias-phone1', 'alias-phone2'],
            isRequired: false,
            isSensitive: true,
            name: 'Sub-Sub-Phone',
            timezoneId: 'UTC',
            children: []
          }
        ]
      }
    ]
  }
]

Here property name is like id, it can't be the same at the same level, but it can in the children. For example Sub-Phone and Sub-Sub-Phone could be named Phone. What is the best way to keep such type of structure in the store that will be easy to change. Because now if want to change name: 'Phone' i should return in reducer full this object with all his children. How i can normalize it?


Solution

  • A common pattern is to follow this guide, to normalize state shape. Do not nest. Create an id that stores the entities. And then create an id that stores the relations (the children, in you scenario). I have built a sample state for you

    const state = {
      objects: {
        id: ['Address', 'Phone', 'Sub-Phone', 'Sub-Sub-Phone'],
        entities: {
          'Address': {
            isRequired: false,
            isSensitive: false,
            timezoneId: 'UTC'
          },
          'Phone': {
            isRequired: true,
            isSensitive: false,
            timezoneId: 'UTC-5'
          },
          'Sub-Phone': {
            isRequired: true,
            isSensitive: false,
            timezoneId: 'UTC-5',
          },
          'Sub-Sub-Phone': {
            isRequired: false,
            isSensitive: true,
            timezoneId: 'UTC',
          }
        }
      },
      children: {
        'Address': [],
        'Phone': ['Sub-Phone'],
        'Sub-Phone': ['Sub-Sub-Phone']
      }
    }
    

    Note that the state has 2 levels: one for the objects, one for the children. The objects stores the ids and the entities. The children, store one array for each object key with its children. Note that in ny example there is only one children in the arrays, but you can have something like

    'Phone': '['Sub-Phone', 'Sub-Phone2', 'Sub-Phone3']