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;
}
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"
}