SlideShare a Scribd company logo
Data normalization &
memoized denormalization
Branislav Holý
1
Data normalization
● A process that transforms denormalized data to normalized data
2
const article = {
id: 'article-1',
title: 'My Awesome Article',
author: {
id: 'user-1',
name: 'John'
}
};
Data normalization
● A process that transforms denormalized data to normalized data
3
const article = {
id: 'article-1',
title: 'My Awesome Article',
author: {
id: 'user-1',
name: 'John'
}
};
const entities = {
users: {
'user-1': {
id: 'user-1',
name: 'John'
}
},
articles: {
...
}
};
Data normalization
● A process that transforms denormalized data to normalized data
4
const article = {
id: 'article-1',
title: 'My Awesome Article',
author: {
id: 'user-1',
name: 'John'
}
};
const entities = {
users: {
'user-1': {
id: 'user-1',
name: 'John'
}
},
articles: {
'article-1': {
id: 'article-1',
title: 'My Awesome Article',
author: 'user-1'
}
}
};
Data normalization
● A process that transforms denormalized data to normalized data
5
const article = {
id: 'article-1',
title: 'My Awesome Article',
author: {
id: 'user-1',
name: 'John'
},
viewers: [{
id: 'user-2',
name: 'Alice'
}, {
id: 'user-1',
name: 'John'
}]
};
Data normalization
● A process that transforms denormalized data to normalized data
6
const article = {
id: 'article-1',
title: 'My Awesome Article',
author: {
id: 'user-1',
name: 'John'
},
viewers: [{
id: 'user-2',
name: 'Alice'
}, {
id: 'user-1',
name: 'John'
}]
};
const entities = {
users: {
'user-1': { ... },
'user-2': { ... }
},
articles: {
'article-1': {
id: 'article-1',
title: 'My Awesome Article',
author: 'user-1',
viewers: ['user-2', 'user-1']
}
};
Should I use it?
● Yes… if your data are entities that have relations between each other
7
Advantages
● Single source of truth
8
const article = {
id: 'article-1',
title: 'My Awesome Article',
author: {
id: 'user-1',
name: 'John'
},
viewers: [{
id: 'user-2',
name: 'Alice'
}, {
id: 'user-1',
name: 'John'
}]
};
Advantages
● Single source of truth
○ Denormalized data
■ name in multiple places
9
const entities = {
users: {
'user-1': {
id: 'user-1',
name: 'John'
},
'user-2': { ... }
},
articles: {
'article-1': {
id: 'article-1',
title: 'My Awesome Article',
author: 'user-1',
viewers: ['user-2', 'user-1']
}
};
Advantages
● Single source of truth
○ Denormalized data
■ name in multiple places
○ Normalized data
■ name in a single place
1
Advantages
● Single source of truth
● Easy to write
○ We have to modify a single place only
11
Disadvantage
● Difficult to read
○ We cannot use:
normalizedArticle.user.name
12
Disadvantage
● Difficult to read
○ We cannot use:
normalizedArticle.user.name
○ The user field is a string!
13
Disadvantage
● Difficult to read
○ We cannot use:
normalizedArticle.user.name
○ The user field is a string!
○ But we can denormalize the article object!
… you’ll see later.
14
Normalizr
● It is a library that converts denormalized data to normalized data
● It uses schema to describe relations between entities
● https://github.com/paularmstrong/normalizr
15
How to normalize data?
● Create schemas for your entities
● Call normalize()
16
Schema
import { schema } from 'normalizr';
const user = new schema.Entity('users');
const article = new schema.Entity('articles', {
author: user,
viewers: [user]
});
17
Schema
import { schema } from 'normalizr';
const user = new schema.Entity('users');
const comment = new schema.Entity('comments', {
commenter: user
});
const article = new schema.Entity('articles', {
author: user,
comments: [comment]
});
18
normalize() function
import { normalize } from 'normalizr';
const normalizedData = normalize(denormalizedData, schema);
○ denormalizedData - nested data (API response)
○ schema - normalizr schema
19
20
const denormalizedArticles = [
{
id: 'article-1',
title: 'My Awesome Article',
author: { id: 'user-1', name: 'John' },
comments: [{
id: 'comment-1',
text: 'Such a great article!',
commenter: { id: 'user-2', name: 'Alice' }
}, {
id: 'comment-2',
text: 'Thanks!',
commenter: { id: 'user-1', name: 'John' }
}]
},
{
id: 'article-2',
title: 'My Terrible Article',
author: { id: 'user-1', name: 'John' },
comments: []
}
]
21
const denormalizedArticles = [
{
id: 'article-1',
title: 'My Awesome Article',
author: { id: 'user-1', name: 'John' },
comments: [{
id: 'comment-1',
text: 'Such a great article!',
commenter: { id: 'user-2', name: 'Alice' }
}, {
id: 'comment-2',
text: 'Thanks!',
commenter: { id: 'user-1', name: 'John' }
}]
},
{
id: 'article-2',
title: 'My Terrible Article',
author: { id: 'user-1', name: 'John' },
comments: []
}
]
normalize(denormalizedArticles, [article]);
22
const denormalizedArticles = [
{
id: 'article-1',
title: 'My Awesome Article',
author: { id: 'user-1', name: 'John' },
comments: [{
id: 'comment-1',
text: 'Such a great article!',
commenter: { id: 'user-2', name: 'Alice' }
}, {
id: 'comment-2',
text: 'Thanks!',
commenter: { id: 'user-1', name: 'John' }
}]
},
{
id: 'article-2',
title: 'My Terrible Article',
author: { id: 'user-1', name: 'John' },
comments: []
}
]
normalize(denormalizedArticles, [article]);
{
entities: {
users: {
'user-1': { id: 'user-1', name: 'John' },
'user-2': { id: 'user-2', name: 'Alice' }
},
comments: { ... },
articles: { ... }
},
result: ['article-1', 'article-2']
}
23
const denormalizedArticles = [
{
id: 'article-1',
title: 'My Awesome Article',
author: { id: 'user-1', name: 'John' },
comments: [{
id: 'comment-1',
text: 'Such a great article!',
commenter: { id: 'user-2', name: 'Alice' }
}, {
id: 'comment-2',
text: 'Thanks!',
commenter: { id: 'user-1', name: 'John' }
}]
},
{
id: 'article-2',
title: 'My Terrible Article',
author: { id: 'user-1', name: 'John' },
comments: []
}
]
normalize(denormalizedArticles, [article]);
{
entities: {
users: { ... },
comments: {
'comment-1': {
id: 'comment-1',
text: 'Such a great article!',
commenter: 'user-2'
},
'comment-2': {
id: 'comment-2',
text: 'Thanks!',
commenter: 'user-1'
}
},
articles: { ... }
},
result: ['article-1', 'article-2']
}
24
const denormalizedArticles = [
{
id: 'article-1',
title: 'My Awesome Article',
author: { id: 'user-1', name: 'John' },
comments: [{
id: 'comment-1',
text: 'Such a great article!',
commenter: { id: 'user-2', name: 'Alice' }
}, {
id: 'comment-2',
text: 'Thanks!',
commenter: { id: 'user-1', name: 'John' }
}]
},
{
id: 'article-2',
title: 'My Terrible Article',
author: { id: 'user-1', name: 'John' },
comments: []
}
]
normalize(denormalizedArticles, [article]);
{
entities: {
users: { ... },
comments: { ... },
articles: {
'article-1': {
id: 'article-1',
title: 'My Awesome Article',
author: 'user-1',
comments: ['comment-1', 'comment-2']
},
'article-2': {
id: 'article-2',
title: 'My Terrible Article',
author: 'user-1',
comments: []
}
}
},
result: ['article-1', 'article-2']
}
How to denormalize data?
● Use the same schemas
● Call denormalize()
○ denormalize(['article-1', 'article-2'], [article], entities);
25
How to denormalize data?
● Use the same schemas
● Call denormalize()
○ denormalize(['article-1', 'article-2'], [article], entities);
○ It denormalizes the whole data structure
○ It does not memoize previously normalized data
26
How to denormalize data?
● Use the same schemas
● Call denormalize()
○ denormalize(['article-1', 'article-2'], [article], entities);
○ It denormalizes the whole data structure
○ It does not memoize previously normalized data
● Use selectors!
27
Reselect
● A selector is a function that gets data from a state
○ const selector = state => state.name; // a simple selector without reselect
● Selectors can compute derived data from a state
○ They keep a single source of truth
● Selectors (with Reselect) are efficient (memoized)
○ They are not recomputed unless one of their arguments is changed
● Selectors (with Reselect) are composable
○ They can be used as input to other selectors
28
Reselect
● The selectors created with
createSelector are memoized
● The first arguments of
createSelector are other
selectors
● The last argument is a function which
has results of the previous selectors
in its input arguments
29
import { normalize } from 'normalizr';
const appState = {
counter: 0,
user: { name: 'John' }
};
const getCounter = state => state.counter;
const getUser = state => state.user;
const getName = createSelector(
getUser,
user => user.name
);
const getUpperCaseName = createSelector(
getUserName,
userName => userName.toUpperCase()
);
const getNameWithCounter = createSelector(
getUpperCaseName,
getCounter,
(userName, num) =,> `${userName} ${num}`
);
Selectors for Users
30
normalize(denormalizedArticles, [article]);
{
entities: {
users: {
'user-1': { id: 'user-1', name: 'John' },
'user-2': { id: 'user-2', name: 'Alice' }
},
comments: { ... },
articles: { ... }
},
result: ['article-1', 'article-2']
}
const getUsers = entities => entities.users;
Selectors for Comments
31
const getUsers = entities => entities.users;
const getNormalizedComments = entities =>
entities.comments;
normalize(denormalizedArticles, [article]);
{
entities: {
users: { ... },
comments: {
'comment-1': {
id: 'comment-1',
text: 'Such a great article!',
commenter: 'user-2'
},
'comment-2': {
id: 'comment-2',
text: 'Thanks!',
commenter: 'user-1'
}
},
articles: { ... }
},
result: ['article-1', 'article-2']
}
Selectors for Comments
const getComments = createSelector(
getNormalizedComments,
getUsers,
(normalizedComments, users) => Object.keys(normalizedComments).reduce(
(comments, commentId) => {
const normalizedComment = normalizedComments[commentId];
const userId = normalizedComment.commenter;
return {
...comments,
[commentId]: {
...normalizedComment,
commenter: users[userId]
}
};
},
{}
)
);
32
Selectors for Articles
33
const getUsers = entities => entities.users;
const getNormalizedComments = entities =>
entities.comments;
const getComments = createSelector(...);
const getNormalizedArticles = entities =>
entities.articles;
normalize(denormalizedArticles, [article]);
{
entities: {
users: { ... },
comments: { ... },
articles: {
'article-1': {
id: 'article-1',
title: 'My Awesome Article',
author: 'user-1',
comments: ['comment-1', 'comment-2']
},
'article-2': {
id: 'article-2',
title: 'My Terrible Article',
author: 'user-1',
comments: []
}
}
},
result: ['article-1', 'article-2']
}
Selectors for Articles
const getArticles = createSelector(
getNormalizedArticles,
getComments,
getUsers,
(normalizedArticles, comments, users) => Object.keys(normalizedArticles).reduce(
(articles, articleId) => {
const normalizedArticle = normalizedArticles[articleId];
const userId = normalizedComment.commenter;
return {
...articles,
[articleId]: {
...normalizedArticle,
author: users[userId],
comments: normalizedArticle.comments.map(commentId => comments[commentId])
}
};
},
{}
));
34
Selectors
35
const getUsers = entities => entities.users;
const getNormalizedComments = entities =>
entities.comments;
const getComments = createSelector(...);
const getNormalizedArticles = entities =>
entities.articles;
const getArticles = createSelector(...);
const normalizedData = {
entities: {
users: { ... },
comments: { ... },
articles: { ... }
},
result: ['article-1', 'article-2']
};
const denormalizedArticles = getArticles(
normalizedData.entities
);
const denormalizedData = normalizedData.result
.map(articleId => denormalizedArticles[articleId]);
36
Thank you!
Don’t forget to use…
37
Thank you!
Don’t forget to use…
38
Thank you!
Any questions?
39
40
Advanced normalizr features
41
● Custom ID attribute
● Process strategy
● Merge strategy
Custom ID attribute
42
● User object: { userId: 'user-1', name: 'John' }
Custom ID attribute
43
● User object: { userId: 'user-1', name: 'John' }
● Schema:
const user = new schema.Entity('users', {}, {
idAttribute: 'userId'
});
Custom ID attribute for M:N
44
[
{
id: 'user-1',
name: 'John',
skills: [
{ level: 10, skill: { id: 'skill-1', name: 'JavaScript' } },
{ level: 1, skill: { id: 'skill-2', name: 'C++' } }
]
},
{
id: 'user-2',
name: 'Alice',
skills: [
{ level: 8, skill: { id: 'skill-1', name: 'JavaScript' } }
]
}
]
Custom ID attribute for M:N
45
const skill = new schema.Entity('skills');
const userSkill = new schema.Entity(
'userSkills',
{ skill },
{
idAttribute: (value, parent) => `${value.skill.id}-${parent.id}`
}
);
const user = new schema.Entity('users', {
skills: [userSkill]
});
Custom ID attribute for M:N
46
{
skills: {
'skill-1': {
id: 'skill-1',
name: 'JavaScript'
},
'skill-2': {
id: 'skill-2',
name: 'C++'
}
},
userSkills: { ... },
users: { ... }
},
result: ['user-1', 'user-2']
}
Custom ID attribute for M:N
47
{
skills: { ... },
userSkills: {
'skill-1-user-1': { level: 10, skill: 'skill-1' },
'skill-2-user-1': { level: 1, skill: 'skill-2' },
'skill-1-user-2': { level: 8, skill: 'skill-1' }
},
users: { ... }
},
result: ['user-1', 'user-2']
}
Custom ID attribute for M:N
48
{
skills: { ... },
userSkills: { ... },
users: {
'user-1': {
id: 'user-1',
name: 'John',
skills: ['skill-1-user-1', 'skill-2-user-1']
},
'user-2': {
id: 'user-2',
name: 'Alice',
skills: ['skill-1-user-2']
}
}},
result: ['user-1', 'user-2']
}
Process strategy
49
● Pre-process entities before the normalization
● Modify the shape of entities
● Add additional data
Process strategy
50
[
{
id: 'user-1',
name: 'John',
skillLevels: [10, 1],
skills: [
{ id: 'skill-1', name: 'JavaScript' },
{ id: 'skill-2', name: 'C++' }
]
},
{
id: 'user-2',
name: 'Alice',
skillLevels: [8],
skills: [{ id: 'skill-1', name: 'JavaScript' }]
}
]
Process strategy
51
const skill = new schema.Entity('skills');
const userSkill = new schema.Entity('userSkills', { skill }, { idAttribute });
const user = new schema.Entity(
'users',
{ skills: [userSkill] },
{
processStrategy: ({ id, name, skillLevels, skills }) => ({
id,
name,
skills: skills.map((skill, index) => ({
level: skillLevels[index],
skill
}))
})
}
);
Process strategy
52
{
skills: { ... },
userSkills: {
'skill-1-user-1': { level: 10, skill: 'skill-1' },
'skill-2-user-1': { level: 1, skill: 'skill-2' },
'skill-1-user-2': { level: 8, skill: 'skill-1' }
},
users: { ... }
},
result: ['user-1', 'user-2']
}
Merge strategy
53
● Merge entities with the same IDs
Merge strategy
54
{
skills: {
'skill-1': {
id: 'skill-1',
name: 'JavaScript'
},
'skill-2': {
id: 'skill-2',
name: 'C++'
}
},
userSkills: { ... },
users: { ... }
},
result: ['user-1', 'user-2']
}
We want user IDs here.
We want user IDs here.
Merge strategy
55
const user = new schema.Entity(
'users',
{ skills: [userSkill] },
{
processStrategy: ({ id, name, skillLevels, skills }) => ({
id,
name,
skills: skills.map((skill, index) => ({
level: skillLevels[index],
skill: {
...skill,
users: [id]
}
}))
})
}
);
Merge strategy
56
const skill = new schema.Entity(
'skills',
{},
{
mergeStrategy: (entityA, entityB) => ({
...entityA,
...entityB,
users: [...entityA.users, ...entityB.users]
})
}
);
Merge strategy
57
{
entities: {
skills: {
'skill-1': {
id: 'skill-1',
name: 'JavaScript',
users: ['user-1', 'user-2']
},
'skill-2': {
id: 'skill-2',
name: 'C++',
users: ['user-1']
}
},
userSkills: { ... },
users: { ... }
},
result: ['user-1', 'user-2']
}
58
Thank you!
Don’t forget to use…
59
Thank you!
Don’t forget to use…
60
Thank you!
Any questions?

More Related Content

What's hot

Getting Started with MongoDB
Getting Started with MongoDBGetting Started with MongoDB
Getting Started with MongoDB
Ahasanul Kalam Akib
 
Jdbc
JdbcJdbc
Html web sql database
Html web sql databaseHtml web sql database
Html web sql database
AbhishekMondal42
 
Service Oriented Architecture-Unit-1-XML Schema
Service Oriented Architecture-Unit-1-XML SchemaService Oriented Architecture-Unit-1-XML Schema
Service Oriented Architecture-Unit-1-XML Schema
Ramco Institute of Technology, Rajapalayam, Tamilnadu, India
 
Sequelize
SequelizeSequelize
Sequelize
Tarek Raihan
 
Kode vb.net
Kode vb.netKode vb.net
Kode vb.net
Azki Nabidin
 
XML and Web Services
XML and Web ServicesXML and Web Services
XML and Web Services
Henry Osborne
 
PHP Database Programming Basics -- Northeast PHP
PHP Database Programming Basics -- Northeast PHPPHP Database Programming Basics -- Northeast PHP
PHP Database Programming Basics -- Northeast PHP
Dave Stokes
 
Truth, deduction, computation; lecture 2
Truth, deduction, computation;   lecture 2Truth, deduction, computation;   lecture 2
Truth, deduction, computation; lecture 2
Vlad Patryshev
 
Pemrograman visual
Pemrograman visualPemrograman visual
Pemrograman visual
Univ. State of Surabaya
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data Objects
Prashant Marathe
 
WebSocket JSON Hackday
WebSocket JSON HackdayWebSocket JSON Hackday
WebSocket JSON Hackday
Somay Nakhal
 
Node-IL Meetup 12/2
Node-IL Meetup 12/2Node-IL Meetup 12/2
Node-IL Meetup 12/2
Ynon Perek
 
Metaworks3
Metaworks3Metaworks3
Metaworks3
uEngine Solutions
 
TDD in the wild
TDD in the wildTDD in the wild
TDD in the wild
Brainhub
 
React in 50 Minutes (DevNexus)
React in 50 Minutes (DevNexus) React in 50 Minutes (DevNexus)
React in 50 Minutes (DevNexus)
Maarten Mulders
 
Xml
XmlXml
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rick Copeland
 

What's hot (18)

Getting Started with MongoDB
Getting Started with MongoDBGetting Started with MongoDB
Getting Started with MongoDB
 
Jdbc
JdbcJdbc
Jdbc
 
Html web sql database
Html web sql databaseHtml web sql database
Html web sql database
 
Service Oriented Architecture-Unit-1-XML Schema
Service Oriented Architecture-Unit-1-XML SchemaService Oriented Architecture-Unit-1-XML Schema
Service Oriented Architecture-Unit-1-XML Schema
 
Sequelize
SequelizeSequelize
Sequelize
 
Kode vb.net
Kode vb.netKode vb.net
Kode vb.net
 
XML and Web Services
XML and Web ServicesXML and Web Services
XML and Web Services
 
PHP Database Programming Basics -- Northeast PHP
PHP Database Programming Basics -- Northeast PHPPHP Database Programming Basics -- Northeast PHP
PHP Database Programming Basics -- Northeast PHP
 
Truth, deduction, computation; lecture 2
Truth, deduction, computation;   lecture 2Truth, deduction, computation;   lecture 2
Truth, deduction, computation; lecture 2
 
Pemrograman visual
Pemrograman visualPemrograman visual
Pemrograman visual
 
PHP Data Objects
PHP Data ObjectsPHP Data Objects
PHP Data Objects
 
WebSocket JSON Hackday
WebSocket JSON HackdayWebSocket JSON Hackday
WebSocket JSON Hackday
 
Node-IL Meetup 12/2
Node-IL Meetup 12/2Node-IL Meetup 12/2
Node-IL Meetup 12/2
 
Metaworks3
Metaworks3Metaworks3
Metaworks3
 
TDD in the wild
TDD in the wildTDD in the wild
TDD in the wild
 
React in 50 Minutes (DevNexus)
React in 50 Minutes (DevNexus) React in 50 Minutes (DevNexus)
React in 50 Minutes (DevNexus)
 
Xml
XmlXml
Xml
 
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
 

Similar to Data normalization & memoized denormalization

Selectors and normalizing state shape
Selectors and normalizing state shapeSelectors and normalizing state shape
Selectors and normalizing state shape
Muntasir Chowdhury
 
How to write bad code in redux (ReactNext 2018)
How to write bad code in redux (ReactNext 2018)How to write bad code in redux (ReactNext 2018)
How to write bad code in redux (ReactNext 2018)
500Tech
 
Kicking ass with redis
Kicking ass with redisKicking ass with redis
Kicking ass with redis
Dvir Volk
 
While writing program in any language, you need to use various variables to s...
While writing program in any language, you need to use various variables to s...While writing program in any language, you need to use various variables to s...
While writing program in any language, you need to use various variables to s...
bhargavi804095
 
11-Classes.ppt
11-Classes.ppt11-Classes.ppt
11-Classes.ppt
basavaraj852759
 
Operator overload rr
Operator overload  rrOperator overload  rr
Operator overload rr
Dhivya Shanmugam
 
Working with JSON
Working with JSONWorking with JSON
Constructors and Destructors
Constructors and DestructorsConstructors and Destructors
Constructors and Destructors
Keyur Vadodariya
 
Lean React - Patterns for High Performance [ploneconf2017]
Lean React - Patterns for High Performance [ploneconf2017]Lean React - Patterns for High Performance [ploneconf2017]
Lean React - Patterns for High Performance [ploneconf2017]
Devon Bernard
 
Jenkins api
Jenkins apiJenkins api
Jenkins api
Arie Bregman
 
JSON & AJAX.pptx
JSON & AJAX.pptxJSON & AJAX.pptx
JSON & AJAX.pptx
dyumna2
 
MongoDB Aggregations Indexing and Profiling
MongoDB Aggregations Indexing and ProfilingMongoDB Aggregations Indexing and Profiling
MongoDB Aggregations Indexing and Profiling
Manish Kapoor
 
MongoDB Performance Tuning
MongoDB Performance TuningMongoDB Performance Tuning
MongoDB Performance Tuning
MongoDB
 
Simple React Todo List
Simple React Todo ListSimple React Todo List
Simple React Todo List
Ritesh Chaudhari
 
Webinarserie: Einführung in MongoDB: “Back to Basics” - Teil 3 - Interaktion ...
Webinarserie: Einführung in MongoDB: “Back to Basics” - Teil 3 - Interaktion ...Webinarserie: Einführung in MongoDB: “Back to Basics” - Teil 3 - Interaktion ...
Webinarserie: Einführung in MongoDB: “Back to Basics” - Teil 3 - Interaktion ...
MongoDB
 
Marc s01 e02-crud-database
Marc s01 e02-crud-databaseMarc s01 e02-crud-database
Marc s01 e02-crud-database
MongoDB
 
C++ - Constructors,Destructors, Operator overloading and Type conversion
C++ - Constructors,Destructors, Operator overloading and Type conversionC++ - Constructors,Destructors, Operator overloading and Type conversion
C++ - Constructors,Destructors, Operator overloading and Type conversion
Hashni T
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
Omnia Helmi
 
MongoDB NoSQL and all of its awesomeness
MongoDB NoSQL and all of its awesomenessMongoDB NoSQL and all of its awesomeness
MongoDB NoSQL and all of its awesomeness
Troy Grosfield
 
Database madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyDatabase madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemy
Jaime Buelta
 

Similar to Data normalization & memoized denormalization (20)

Selectors and normalizing state shape
Selectors and normalizing state shapeSelectors and normalizing state shape
Selectors and normalizing state shape
 
How to write bad code in redux (ReactNext 2018)
How to write bad code in redux (ReactNext 2018)How to write bad code in redux (ReactNext 2018)
How to write bad code in redux (ReactNext 2018)
 
Kicking ass with redis
Kicking ass with redisKicking ass with redis
Kicking ass with redis
 
While writing program in any language, you need to use various variables to s...
While writing program in any language, you need to use various variables to s...While writing program in any language, you need to use various variables to s...
While writing program in any language, you need to use various variables to s...
 
11-Classes.ppt
11-Classes.ppt11-Classes.ppt
11-Classes.ppt
 
Operator overload rr
Operator overload  rrOperator overload  rr
Operator overload rr
 
Working with JSON
Working with JSONWorking with JSON
Working with JSON
 
Constructors and Destructors
Constructors and DestructorsConstructors and Destructors
Constructors and Destructors
 
Lean React - Patterns for High Performance [ploneconf2017]
Lean React - Patterns for High Performance [ploneconf2017]Lean React - Patterns for High Performance [ploneconf2017]
Lean React - Patterns for High Performance [ploneconf2017]
 
Jenkins api
Jenkins apiJenkins api
Jenkins api
 
JSON & AJAX.pptx
JSON & AJAX.pptxJSON & AJAX.pptx
JSON & AJAX.pptx
 
MongoDB Aggregations Indexing and Profiling
MongoDB Aggregations Indexing and ProfilingMongoDB Aggregations Indexing and Profiling
MongoDB Aggregations Indexing and Profiling
 
MongoDB Performance Tuning
MongoDB Performance TuningMongoDB Performance Tuning
MongoDB Performance Tuning
 
Simple React Todo List
Simple React Todo ListSimple React Todo List
Simple React Todo List
 
Webinarserie: Einführung in MongoDB: “Back to Basics” - Teil 3 - Interaktion ...
Webinarserie: Einführung in MongoDB: “Back to Basics” - Teil 3 - Interaktion ...Webinarserie: Einführung in MongoDB: “Back to Basics” - Teil 3 - Interaktion ...
Webinarserie: Einführung in MongoDB: “Back to Basics” - Teil 3 - Interaktion ...
 
Marc s01 e02-crud-database
Marc s01 e02-crud-databaseMarc s01 e02-crud-database
Marc s01 e02-crud-database
 
C++ - Constructors,Destructors, Operator overloading and Type conversion
C++ - Constructors,Destructors, Operator overloading and Type conversionC++ - Constructors,Destructors, Operator overloading and Type conversion
C++ - Constructors,Destructors, Operator overloading and Type conversion
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
 
MongoDB NoSQL and all of its awesomeness
MongoDB NoSQL and all of its awesomenessMongoDB NoSQL and all of its awesomeness
MongoDB NoSQL and all of its awesomeness
 
Database madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyDatabase madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemy
 

Recently uploaded

GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
Green Software Development
 
Lecture 2 - software testing SE 412.pptx
Lecture 2 - software testing SE 412.pptxLecture 2 - software testing SE 412.pptx
Lecture 2 - software testing SE 412.pptx
TaghreedAltamimi
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
Marcin Chrost
 
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
mz5nrf0n
 
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdfTop Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
VALiNTRY360
 
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
XfilesPro
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
Green Software Development
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
Drona Infotech
 
Unveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdfUnveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdf
brainerhub1
 
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
Bert Jan Schrijver
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
Green Software Development
 
UI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design SystemUI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design System
Peter Muessig
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
Peter Muessig
 
一比一原版(USF毕业证)旧金山大学毕业证如何办理
一比一原版(USF毕业证)旧金山大学毕业证如何办理一比一原版(USF毕业证)旧金山大学毕业证如何办理
一比一原版(USF毕业证)旧金山大学毕业证如何办理
dakas1
 
Malibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed RoundMalibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed Round
sjcobrien
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Łukasz Chruściel
 
Microservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we workMicroservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we work
Sven Peters
 
What next after learning python programming basics
What next after learning python programming basicsWhat next after learning python programming basics
What next after learning python programming basics
Rakesh Kumar R
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
Philip Schwarz
 
Odoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
Odoo ERP Vs. Traditional ERP Systems – A Comparative AnalysisOdoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
Odoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
Envertis Software Solutions
 

Recently uploaded (20)

GreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-JurisicGreenCode-A-VSCode-Plugin--Dario-Jurisic
GreenCode-A-VSCode-Plugin--Dario-Jurisic
 
Lecture 2 - software testing SE 412.pptx
Lecture 2 - software testing SE 412.pptxLecture 2 - software testing SE 412.pptx
Lecture 2 - software testing SE 412.pptx
 
Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !Enums On Steroids - let's look at sealed classes !
Enums On Steroids - let's look at sealed classes !
 
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
 
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdfTop Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
Top Benefits of Using Salesforce Healthcare CRM for Patient Management.pdf
 
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
Everything You Need to Know About X-Sign: The eSign Functionality of XfilesPr...
 
Energy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina JonuziEnergy consumption of Database Management - Florina Jonuzi
Energy consumption of Database Management - Florina Jonuzi
 
Mobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona InfotechMobile App Development Company In Noida | Drona Infotech
Mobile App Development Company In Noida | Drona Infotech
 
Unveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdfUnveiling the Advantages of Agile Software Development.pdf
Unveiling the Advantages of Agile Software Development.pdf
 
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
J-Spring 2024 - Going serverless with Quarkus, GraalVM native images and AWS ...
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
 
UI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design SystemUI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design System
 
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s EcosystemUI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
UI5con 2024 - Keynote: Latest News about UI5 and it’s Ecosystem
 
一比一原版(USF毕业证)旧金山大学毕业证如何办理
一比一原版(USF毕业证)旧金山大学毕业证如何办理一比一原版(USF毕业证)旧金山大学毕业证如何办理
一比一原版(USF毕业证)旧金山大学毕业证如何办理
 
Malibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed RoundMalibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed Round
 
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️Need for Speed: Removing speed bumps from your Symfony projects ⚡️
Need for Speed: Removing speed bumps from your Symfony projects ⚡️
 
Microservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we workMicroservice Teams - How the cloud changes the way we work
Microservice Teams - How the cloud changes the way we work
 
What next after learning python programming basics
What next after learning python programming basicsWhat next after learning python programming basics
What next after learning python programming basics
 
Hand Rolled Applicative User Validation Code Kata
Hand Rolled Applicative User ValidationCode KataHand Rolled Applicative User ValidationCode Kata
Hand Rolled Applicative User Validation Code Kata
 
Odoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
Odoo ERP Vs. Traditional ERP Systems – A Comparative AnalysisOdoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
Odoo ERP Vs. Traditional ERP Systems – A Comparative Analysis
 

Data normalization & memoized denormalization

  • 1. Data normalization & memoized denormalization Branislav Holý 1
  • 2. Data normalization ● A process that transforms denormalized data to normalized data 2 const article = { id: 'article-1', title: 'My Awesome Article', author: { id: 'user-1', name: 'John' } };
  • 3. Data normalization ● A process that transforms denormalized data to normalized data 3 const article = { id: 'article-1', title: 'My Awesome Article', author: { id: 'user-1', name: 'John' } }; const entities = { users: { 'user-1': { id: 'user-1', name: 'John' } }, articles: { ... } };
  • 4. Data normalization ● A process that transforms denormalized data to normalized data 4 const article = { id: 'article-1', title: 'My Awesome Article', author: { id: 'user-1', name: 'John' } }; const entities = { users: { 'user-1': { id: 'user-1', name: 'John' } }, articles: { 'article-1': { id: 'article-1', title: 'My Awesome Article', author: 'user-1' } } };
  • 5. Data normalization ● A process that transforms denormalized data to normalized data 5 const article = { id: 'article-1', title: 'My Awesome Article', author: { id: 'user-1', name: 'John' }, viewers: [{ id: 'user-2', name: 'Alice' }, { id: 'user-1', name: 'John' }] };
  • 6. Data normalization ● A process that transforms denormalized data to normalized data 6 const article = { id: 'article-1', title: 'My Awesome Article', author: { id: 'user-1', name: 'John' }, viewers: [{ id: 'user-2', name: 'Alice' }, { id: 'user-1', name: 'John' }] }; const entities = { users: { 'user-1': { ... }, 'user-2': { ... } }, articles: { 'article-1': { id: 'article-1', title: 'My Awesome Article', author: 'user-1', viewers: ['user-2', 'user-1'] } };
  • 7. Should I use it? ● Yes… if your data are entities that have relations between each other 7
  • 9. const article = { id: 'article-1', title: 'My Awesome Article', author: { id: 'user-1', name: 'John' }, viewers: [{ id: 'user-2', name: 'Alice' }, { id: 'user-1', name: 'John' }] }; Advantages ● Single source of truth ○ Denormalized data ■ name in multiple places 9
  • 10. const entities = { users: { 'user-1': { id: 'user-1', name: 'John' }, 'user-2': { ... } }, articles: { 'article-1': { id: 'article-1', title: 'My Awesome Article', author: 'user-1', viewers: ['user-2', 'user-1'] } }; Advantages ● Single source of truth ○ Denormalized data ■ name in multiple places ○ Normalized data ■ name in a single place 1
  • 11. Advantages ● Single source of truth ● Easy to write ○ We have to modify a single place only 11
  • 12. Disadvantage ● Difficult to read ○ We cannot use: normalizedArticle.user.name 12
  • 13. Disadvantage ● Difficult to read ○ We cannot use: normalizedArticle.user.name ○ The user field is a string! 13
  • 14. Disadvantage ● Difficult to read ○ We cannot use: normalizedArticle.user.name ○ The user field is a string! ○ But we can denormalize the article object! … you’ll see later. 14
  • 15. Normalizr ● It is a library that converts denormalized data to normalized data ● It uses schema to describe relations between entities ● https://github.com/paularmstrong/normalizr 15
  • 16. How to normalize data? ● Create schemas for your entities ● Call normalize() 16
  • 17. Schema import { schema } from 'normalizr'; const user = new schema.Entity('users'); const article = new schema.Entity('articles', { author: user, viewers: [user] }); 17
  • 18. Schema import { schema } from 'normalizr'; const user = new schema.Entity('users'); const comment = new schema.Entity('comments', { commenter: user }); const article = new schema.Entity('articles', { author: user, comments: [comment] }); 18
  • 19. normalize() function import { normalize } from 'normalizr'; const normalizedData = normalize(denormalizedData, schema); ○ denormalizedData - nested data (API response) ○ schema - normalizr schema 19
  • 20. 20 const denormalizedArticles = [ { id: 'article-1', title: 'My Awesome Article', author: { id: 'user-1', name: 'John' }, comments: [{ id: 'comment-1', text: 'Such a great article!', commenter: { id: 'user-2', name: 'Alice' } }, { id: 'comment-2', text: 'Thanks!', commenter: { id: 'user-1', name: 'John' } }] }, { id: 'article-2', title: 'My Terrible Article', author: { id: 'user-1', name: 'John' }, comments: [] } ]
  • 21. 21 const denormalizedArticles = [ { id: 'article-1', title: 'My Awesome Article', author: { id: 'user-1', name: 'John' }, comments: [{ id: 'comment-1', text: 'Such a great article!', commenter: { id: 'user-2', name: 'Alice' } }, { id: 'comment-2', text: 'Thanks!', commenter: { id: 'user-1', name: 'John' } }] }, { id: 'article-2', title: 'My Terrible Article', author: { id: 'user-1', name: 'John' }, comments: [] } ] normalize(denormalizedArticles, [article]);
  • 22. 22 const denormalizedArticles = [ { id: 'article-1', title: 'My Awesome Article', author: { id: 'user-1', name: 'John' }, comments: [{ id: 'comment-1', text: 'Such a great article!', commenter: { id: 'user-2', name: 'Alice' } }, { id: 'comment-2', text: 'Thanks!', commenter: { id: 'user-1', name: 'John' } }] }, { id: 'article-2', title: 'My Terrible Article', author: { id: 'user-1', name: 'John' }, comments: [] } ] normalize(denormalizedArticles, [article]); { entities: { users: { 'user-1': { id: 'user-1', name: 'John' }, 'user-2': { id: 'user-2', name: 'Alice' } }, comments: { ... }, articles: { ... } }, result: ['article-1', 'article-2'] }
  • 23. 23 const denormalizedArticles = [ { id: 'article-1', title: 'My Awesome Article', author: { id: 'user-1', name: 'John' }, comments: [{ id: 'comment-1', text: 'Such a great article!', commenter: { id: 'user-2', name: 'Alice' } }, { id: 'comment-2', text: 'Thanks!', commenter: { id: 'user-1', name: 'John' } }] }, { id: 'article-2', title: 'My Terrible Article', author: { id: 'user-1', name: 'John' }, comments: [] } ] normalize(denormalizedArticles, [article]); { entities: { users: { ... }, comments: { 'comment-1': { id: 'comment-1', text: 'Such a great article!', commenter: 'user-2' }, 'comment-2': { id: 'comment-2', text: 'Thanks!', commenter: 'user-1' } }, articles: { ... } }, result: ['article-1', 'article-2'] }
  • 24. 24 const denormalizedArticles = [ { id: 'article-1', title: 'My Awesome Article', author: { id: 'user-1', name: 'John' }, comments: [{ id: 'comment-1', text: 'Such a great article!', commenter: { id: 'user-2', name: 'Alice' } }, { id: 'comment-2', text: 'Thanks!', commenter: { id: 'user-1', name: 'John' } }] }, { id: 'article-2', title: 'My Terrible Article', author: { id: 'user-1', name: 'John' }, comments: [] } ] normalize(denormalizedArticles, [article]); { entities: { users: { ... }, comments: { ... }, articles: { 'article-1': { id: 'article-1', title: 'My Awesome Article', author: 'user-1', comments: ['comment-1', 'comment-2'] }, 'article-2': { id: 'article-2', title: 'My Terrible Article', author: 'user-1', comments: [] } } }, result: ['article-1', 'article-2'] }
  • 25. How to denormalize data? ● Use the same schemas ● Call denormalize() ○ denormalize(['article-1', 'article-2'], [article], entities); 25
  • 26. How to denormalize data? ● Use the same schemas ● Call denormalize() ○ denormalize(['article-1', 'article-2'], [article], entities); ○ It denormalizes the whole data structure ○ It does not memoize previously normalized data 26
  • 27. How to denormalize data? ● Use the same schemas ● Call denormalize() ○ denormalize(['article-1', 'article-2'], [article], entities); ○ It denormalizes the whole data structure ○ It does not memoize previously normalized data ● Use selectors! 27
  • 28. Reselect ● A selector is a function that gets data from a state ○ const selector = state => state.name; // a simple selector without reselect ● Selectors can compute derived data from a state ○ They keep a single source of truth ● Selectors (with Reselect) are efficient (memoized) ○ They are not recomputed unless one of their arguments is changed ● Selectors (with Reselect) are composable ○ They can be used as input to other selectors 28
  • 29. Reselect ● The selectors created with createSelector are memoized ● The first arguments of createSelector are other selectors ● The last argument is a function which has results of the previous selectors in its input arguments 29 import { normalize } from 'normalizr'; const appState = { counter: 0, user: { name: 'John' } }; const getCounter = state => state.counter; const getUser = state => state.user; const getName = createSelector( getUser, user => user.name ); const getUpperCaseName = createSelector( getUserName, userName => userName.toUpperCase() ); const getNameWithCounter = createSelector( getUpperCaseName, getCounter, (userName, num) =,> `${userName} ${num}` );
  • 30. Selectors for Users 30 normalize(denormalizedArticles, [article]); { entities: { users: { 'user-1': { id: 'user-1', name: 'John' }, 'user-2': { id: 'user-2', name: 'Alice' } }, comments: { ... }, articles: { ... } }, result: ['article-1', 'article-2'] } const getUsers = entities => entities.users;
  • 31. Selectors for Comments 31 const getUsers = entities => entities.users; const getNormalizedComments = entities => entities.comments; normalize(denormalizedArticles, [article]); { entities: { users: { ... }, comments: { 'comment-1': { id: 'comment-1', text: 'Such a great article!', commenter: 'user-2' }, 'comment-2': { id: 'comment-2', text: 'Thanks!', commenter: 'user-1' } }, articles: { ... } }, result: ['article-1', 'article-2'] }
  • 32. Selectors for Comments const getComments = createSelector( getNormalizedComments, getUsers, (normalizedComments, users) => Object.keys(normalizedComments).reduce( (comments, commentId) => { const normalizedComment = normalizedComments[commentId]; const userId = normalizedComment.commenter; return { ...comments, [commentId]: { ...normalizedComment, commenter: users[userId] } }; }, {} ) ); 32
  • 33. Selectors for Articles 33 const getUsers = entities => entities.users; const getNormalizedComments = entities => entities.comments; const getComments = createSelector(...); const getNormalizedArticles = entities => entities.articles; normalize(denormalizedArticles, [article]); { entities: { users: { ... }, comments: { ... }, articles: { 'article-1': { id: 'article-1', title: 'My Awesome Article', author: 'user-1', comments: ['comment-1', 'comment-2'] }, 'article-2': { id: 'article-2', title: 'My Terrible Article', author: 'user-1', comments: [] } } }, result: ['article-1', 'article-2'] }
  • 34. Selectors for Articles const getArticles = createSelector( getNormalizedArticles, getComments, getUsers, (normalizedArticles, comments, users) => Object.keys(normalizedArticles).reduce( (articles, articleId) => { const normalizedArticle = normalizedArticles[articleId]; const userId = normalizedComment.commenter; return { ...articles, [articleId]: { ...normalizedArticle, author: users[userId], comments: normalizedArticle.comments.map(commentId => comments[commentId]) } }; }, {} )); 34
  • 35. Selectors 35 const getUsers = entities => entities.users; const getNormalizedComments = entities => entities.comments; const getComments = createSelector(...); const getNormalizedArticles = entities => entities.articles; const getArticles = createSelector(...); const normalizedData = { entities: { users: { ... }, comments: { ... }, articles: { ... } }, result: ['article-1', 'article-2'] }; const denormalizedArticles = getArticles( normalizedData.entities ); const denormalizedData = normalizedData.result .map(articleId => denormalizedArticles[articleId]);
  • 39. 39
  • 40. 40
  • 41. Advanced normalizr features 41 ● Custom ID attribute ● Process strategy ● Merge strategy
  • 42. Custom ID attribute 42 ● User object: { userId: 'user-1', name: 'John' }
  • 43. Custom ID attribute 43 ● User object: { userId: 'user-1', name: 'John' } ● Schema: const user = new schema.Entity('users', {}, { idAttribute: 'userId' });
  • 44. Custom ID attribute for M:N 44 [ { id: 'user-1', name: 'John', skills: [ { level: 10, skill: { id: 'skill-1', name: 'JavaScript' } }, { level: 1, skill: { id: 'skill-2', name: 'C++' } } ] }, { id: 'user-2', name: 'Alice', skills: [ { level: 8, skill: { id: 'skill-1', name: 'JavaScript' } } ] } ]
  • 45. Custom ID attribute for M:N 45 const skill = new schema.Entity('skills'); const userSkill = new schema.Entity( 'userSkills', { skill }, { idAttribute: (value, parent) => `${value.skill.id}-${parent.id}` } ); const user = new schema.Entity('users', { skills: [userSkill] });
  • 46. Custom ID attribute for M:N 46 { skills: { 'skill-1': { id: 'skill-1', name: 'JavaScript' }, 'skill-2': { id: 'skill-2', name: 'C++' } }, userSkills: { ... }, users: { ... } }, result: ['user-1', 'user-2'] }
  • 47. Custom ID attribute for M:N 47 { skills: { ... }, userSkills: { 'skill-1-user-1': { level: 10, skill: 'skill-1' }, 'skill-2-user-1': { level: 1, skill: 'skill-2' }, 'skill-1-user-2': { level: 8, skill: 'skill-1' } }, users: { ... } }, result: ['user-1', 'user-2'] }
  • 48. Custom ID attribute for M:N 48 { skills: { ... }, userSkills: { ... }, users: { 'user-1': { id: 'user-1', name: 'John', skills: ['skill-1-user-1', 'skill-2-user-1'] }, 'user-2': { id: 'user-2', name: 'Alice', skills: ['skill-1-user-2'] } }}, result: ['user-1', 'user-2'] }
  • 49. Process strategy 49 ● Pre-process entities before the normalization ● Modify the shape of entities ● Add additional data
  • 50. Process strategy 50 [ { id: 'user-1', name: 'John', skillLevels: [10, 1], skills: [ { id: 'skill-1', name: 'JavaScript' }, { id: 'skill-2', name: 'C++' } ] }, { id: 'user-2', name: 'Alice', skillLevels: [8], skills: [{ id: 'skill-1', name: 'JavaScript' }] } ]
  • 51. Process strategy 51 const skill = new schema.Entity('skills'); const userSkill = new schema.Entity('userSkills', { skill }, { idAttribute }); const user = new schema.Entity( 'users', { skills: [userSkill] }, { processStrategy: ({ id, name, skillLevels, skills }) => ({ id, name, skills: skills.map((skill, index) => ({ level: skillLevels[index], skill })) }) } );
  • 52. Process strategy 52 { skills: { ... }, userSkills: { 'skill-1-user-1': { level: 10, skill: 'skill-1' }, 'skill-2-user-1': { level: 1, skill: 'skill-2' }, 'skill-1-user-2': { level: 8, skill: 'skill-1' } }, users: { ... } }, result: ['user-1', 'user-2'] }
  • 53. Merge strategy 53 ● Merge entities with the same IDs
  • 54. Merge strategy 54 { skills: { 'skill-1': { id: 'skill-1', name: 'JavaScript' }, 'skill-2': { id: 'skill-2', name: 'C++' } }, userSkills: { ... }, users: { ... } }, result: ['user-1', 'user-2'] } We want user IDs here. We want user IDs here.
  • 55. Merge strategy 55 const user = new schema.Entity( 'users', { skills: [userSkill] }, { processStrategy: ({ id, name, skillLevels, skills }) => ({ id, name, skills: skills.map((skill, index) => ({ level: skillLevels[index], skill: { ...skill, users: [id] } })) }) } );
  • 56. Merge strategy 56 const skill = new schema.Entity( 'skills', {}, { mergeStrategy: (entityA, entityB) => ({ ...entityA, ...entityB, users: [...entityA.users, ...entityB.users] }) } );
  • 57. Merge strategy 57 { entities: { skills: { 'skill-1': { id: 'skill-1', name: 'JavaScript', users: ['user-1', 'user-2'] }, 'skill-2': { id: 'skill-2', name: 'C++', users: ['user-1'] } }, userSkills: { ... }, users: { ... } }, result: ['user-1', 'user-2'] }