Search code examples
javascriptreduxnormalizr

Two Way Link Using Normalizr


I have a list of regions, which I get from an API. In this list, there are multiple buildings. This will look like this in JS:

  const regions = [
  {
    guid: 'REGION1-GUID',
    name: 'Region 1',
    buildings: [
      {
        guid: 'REGION1-BUILDING1-GUID',
        name: 'Region 1 Building 1'
      },
      {
        guid: 'REGION1-BUILDING2-GUID',
        name: 'Region 1 Building 2'
      }
    ]
  },
  {
    guid: 'REGION2-GUID',
    name: 'Region 2',
    buildings: [
      {
        guid: 'REGION2-BUILDING1-GUID',
        name: 'Region 2 Building 1'
      },
      {
        guid: 'REGION2-BUIDLING2-GUID',
        name: 'Region 2 Building 2'
      }
    ]
  }
];

Now I want to normalize this JS Object using normalizr. What I want to do later is to get the region from a building.

So I tried to do the following:

// Define the buildings schema
const building = new schema.Entity('building', {}, { idAttribute: 'guid' });

// Define the regions schema
const region = new schema.Entity(
  'regions',
  {
    buildings: [building]
  },
  { idAttribute: 'guid' }
);

const regionList = [region];

const normalizeData = () => {
  const normalizedData = normalize(data, regionList);

This does normalize my object, the normalizedData is like this:

{  
   "entities":{  
      "building":{  
         "REGION1-BUILDING1-GUID":{  
            "guid":"REGION1-BUILDING1-GUID",
            "name":"Region 1 Building 1"
         },
         "REGION1-BUILDING2-GUID":{  
            "guid":"REGION1-BUILDING2-GUID",
            "name":"Region 1 Building 2"
         },
         "REGION2-BUILDING1-GUID":{  
            "guid":"REGION2-BUILDING1-GUID",
            "name":"Region 2 Building 1"
         },
         "REGION2-BUIDLING2-GUID":{  
            "guid":"REGION2-BUIDLING2-GUID",
            "name":"Region 2 Building 2"
         }
      },
      "regions":{  
         "REGION1-GUID":{  
            "guid":"REGION1-GUID",
            "name":"Region 1",
            "buildings":[  
               "REGION1-BUILDING1-GUID",
               "REGION1-BUILDING2-GUID"
            ]
         },
         "REGION2-GUID":{  
            "guid":"REGION2-GUID",
            "name":"Region 2",
            "buildings":[  
               "REGION2-BUILDING1-GUID",
               "REGION2-BUIDLING2-GUID"
            ]
         }
      }
   },
   "result":[  
      "REGION1-GUID",
      "REGION2-GUID"
   ]
}

But to get the Region of a building i need to iterate over every region and check if the building is contained in the list. I will not get any added value trough the normalization.

It would be perfect if I am able to link in both direction. Every region entitiy has a list of building guids and every building has one region guid.

Is there any way to archieve this in normalizr? What would be the best approach?

Thank you for your help.


Solution

  • I tried some things and found a working solution. I don't know if there is any better approach, but it's very clean code and it's working.

    I just had to change the definition of the building entity to:

    // Define buildings schema
    const building = new schema.Entity(
      'building',
      {},
      {
        idAttribute: 'guid',
        processStrategy: (entity, parent) => ({ ...entity, regionGuid: parent.guid })
      }
    );
    

    This will add the property "regionGuid" to the building which holds the guid from the region.