How to define schema for recursive model with Normalizr

8.1k views Asked by At

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: [] },
    }]
  }
}
2

There are 2 answers

4
Paul Armstrong On BEST ANSWER

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
}
0
zarcode On

If someone has the case of nested objects of same "type", for example "sections" and top level structure is array of "sections" too, like this:

const data = [
    {
      id: 1,
      sections:[{ id: 4, sections: [ { id: 5, sections: [] } ] }]
    }, 
    {
      id: 2,
      sections:[]
    }, 
    {
      id: 3,
      sections:[]
    }
  ]

here one way to "unnest" them:

import {schema, normalize} from "normalizr";

const child = new schema.Entity("sections");
const sections = new schema.Array(child);
child.define({sections});

const topLevel = new schema.Entity("sections", {
    sections
});

const customSchema = [topLevel];

console.log(normalize(data, customSchema));

What you will get is:

{
   "entities":{
      "sections":{
         "1":{
            "id":1,
            "sections":[
               4
            ]
         },
         "2":{
            "id":2,
            "sections":[

            ]
         },
         "3":{
            "id":3,
            "sections":[

            ]
         },
         "4":{
            "id":4,
            "sections":[
               5
            ]
         },
         "5":{
            "id":5,
            "sections":[

            ]
         }
      }
   },
   "result":[
      1,
      2,
      3
   ]
}