Search code examples
javascriptreactjsreduxnormalizr

How to define schema for recursive model with Normalizr


Having a bit of an issue trying to normalise a payload, that contains a nested schema of the same type as the parent using Normalizr

For example I have the initial object (menu) which has a child (sections) which is an array of objects (section), which can go n deep.

{
  id: 123,
  sections: [{
    id: 1,
    sections:[{ id: 4, sections: [ id: 5, sections: [] ] }]
  }, {
    id: 2,
    sections:[]
  }, {
    id: 3,
    sections:[]
  }]
}

I started by creating a menu schema, that had sections in the definition that linked to a sections schema, that worked for the first pass, but then wouldn't handle children of sections, so I added a subsequent definition within the section schema with the same name (was worth a shot) but it didn't work.

const section = new schema.Entity('sections')

const sections = new schema.Entity('sections', {
  sections: section
})

const menu = new schema.Entity('menu', { 
  sections: [ sections ]
})

section.define({ sections })

I'm hoping to end up with the object below:

{
  entities: {
    menu: {
      sections: [1, 2, 3]
    },
    sections: [{
      1: { id: 1, sections: [4] },
      2: { id: 2, sections: [] },
      3: { id: 3, sections: [] },
      4: { id: 4, sections: [5] },
      5: { id: 5, sections: [] },
    }]
  }
}

Solution

  • Your sections schema should be an Array.

    const section = new schema.Entity('sections')
    const sections = new schema.Array(section);
    section.define({ sections });
    const menu = new schema.Entity('menu', { sections });
    

    Then, in using it...

    const data = {
      id: 123,
      sections: [{
        id: 1,
        sections:[{ id: 4, sections: [ { id: 5, sections: [] } ] }]
      }, {
        id: 2,
        sections:[]
      }, {
        id: 3,
        sections:[]
      }]
    };
    
    normalize(data, menu)
    

    Will return:

    {
      "entities": {
        "sections": {
          "1": { "id": 1, "sections": [ 4 ] },
          "2": { "id": 2, "sections": [] }, 
          "3": { "id": 3, "sections": [] },
          "4": { "id": 4, "sections": [ 5 ] },
          "5": { "id": 5, "sections": [] }
        },
        "menu": {
          "123": { "id": 123, "sections": [ 1, 2, 3 ] }
        }
      },
      "result": 123
    }