1

I am trying to normalize an array of data of the following structure Array<Application>. using the createEntityAdapter.

After fetching the data with a createAsyncThunk and returning them, I did set them in the extraReducers like this:

applicationsAdapter.setAll(state, action.payload)

In the Redux DevTools I could see that the data look like this:

{
    applications: {
      ids: [
        '60a684fb90957536f185ea88',
      ],
      entities: {
        '60a684fb90957536f185ea88': {
          id: '60a684fb90957536f185ea88',
          title: 'Article1',
          description: 'The best article ever',
          groups: [
            {
              id: 'bPDGd8uOkmKKAO3FyoTKE',
              title: 'Group 1',
              voters: [
                {
                  user: {
                    uid: '344bc9b8-671b-4de5-ab2d-a619ea34d0ba',
                    username: 'tran',
                  },
                  vote: 'DECLINED'
                }
              ]
            }
          ],
          deadline: "2021-05-20",
          budget: 0,
          createdAt: '2021-05-20',
          createdBy: {
            uid: 'ab2a8f19-c851-4a5f-9438-1000bfde205a',
            username: 'admin',
          },
     },
}

QUESTION: The data is not fully normalized. How can I normalize the groups, voters and users objects?

Here are the interfaces:

export interface Application {
    id: string;
    title: string;
    description: string;
    groups: Array<GroupElement>;
    deadline: string;
    budget?: number;
    createdAt: string;
    createdBy: User;
}


export interface GroupElement {
    id: string;
    title: string;
    voters: Array<Voter>;
}

export interface User {
    uid: string;
    username: string;
}

export interface Voter {
    user: User;
    vote: Decision;
}
Georgios
  • 861
  • 2
  • 12
  • 30

2 Answers2

1

createEntityAdapter does not perform any sort of relationship normalizing on its own. You need to use normalizr for that.

This is a tough one to normalize due to the Voter object which lacks an id property of its own. I had to piece one together.

import { schema, normalize } from "normalizr";

const user = new schema.Entity("user", {}, { idAttribute: "uid" });

const voter = new schema.Entity(
  "voter",
  {
    user: user
  },
  {
    idAttribute: (object) => `${object.vote}-${object.user.uid}`
  }
);

const group = new schema.Entity("group", {
  voters: [voter]
});

const application = new schema.Entity("application", {
  createdBy: user,
  groups: [group]
});

normalize(entity, application);

That will transform your data into:

{
  "entities": {
    "user": {
      "ab2a8f19-c851-4a5f-9438-1000bfde205a": {
        "uid": "ab2a8f19-c851-4a5f-9438-1000bfde205a",
        "username": "admin"
      },
      "344bc9b8-671b-4de5-ab2d-a619ea34d0ba": {
        "uid": "344bc9b8-671b-4de5-ab2d-a619ea34d0ba",
        "username": "tran"
      }
    },
    "voter": {
      "DECLINED-344bc9b8-671b-4de5-ab2d-a619ea34d0ba": {
        "user": "344bc9b8-671b-4de5-ab2d-a619ea34d0ba",
        "vote": "DECLINED"
      }
    },
    "group": {
      "bPDGd8uOkmKKAO3FyoTKE": {
        "id": "bPDGd8uOkmKKAO3FyoTKE",
        "title": "Group 1",
        "voters": ["DECLINED-344bc9b8-671b-4de5-ab2d-a619ea34d0ba"]
      }
    },
    "application": {
      "60a684fb90957536f185ea88": {
        "id": "60a684fb90957536f185ea88",
        "title": "Article1",
        "description": "The best article ever",
        "groups": ["bPDGd8uOkmKKAO3FyoTKE"],
        "deadline": "2021-05-20",
        "budget": 0,
        "createdAt": "2021-05-20",
        "createdBy": "ab2a8f19-c851-4a5f-9438-1000bfde205a"
      }
    }
  },
  "result": "60a684fb90957536f185ea88"
}
Linda Paiste
  • 38,446
  • 6
  • 64
  • 102
  • This is great! I definitely thought that `createEntityAdapter` does a 1st layer normalization since I do have within it `ids` and `entities`. Do I then put the data into the `createEntityAdapter` after normalizing it? How would this look (implementation)? – Georgios May 24 '21 at 10:03
0

I agree with you. createEntityAdapter appears to do the first layer normalization, hence the output "ids / entities". I'm not sure using it alongside normalizr is the way to go because createEntityAdapter's API exposes some methods to put data back into it like addONe or addMany and if you use it with normalizr to normalize the nested data, I don't think you can use the outer-most's methods such as addOne or Addmany for the nested ones that you normalized with the library (normalizr).

  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/30060514) – Jmb Oct 13 '21 at 06:36