How to store relational data inside Redux
Tags: react, redux, javascript, patterns
Published: 2019-04-03 19:44:17

---
title: How to store relational data inside Redux
published: true
description: 
tags: react, redux, javascript, patterns
---

![](https://thepracticaldev.s3.amazonaws.com/i/wete0e9ivdsi5wjj6zm9.jpg)

_Photo by [Tobias Fischer](https://unsplash.com/photos/PkbZahEG2Ng?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/)_

Sooner or later, all frontend developers need to save relational data in a Redux store.

## TL;DR

Follow the [advice](https://firebase.google.com/docs/database/web/structure-data) of Firebase, they are very useful.

## Data

Whether they come from APIs or static payloads, based on relational DBs or not, the data has relationships between them.

We will define **resources** all those types of data that could have relations with other **resources**.

An example resource could be a post from our personal blog.

This **post** will have a 1:1 relationship with the **author** (from the point of view of the **post**, we will see that an **author** will have a 1:N relationship with **posts**) and a 1:N relationship with **comments**.

## An inefficient structure

Let's say that our personal blog should only present a list of posts and a detail page for each of them.

For this specific example we could have, in our Redux store, a first level key containing all our posts indexed by id. Within each one we could nest the author's data and comments.

```javascript
const store = {
  posts: {
    'p123': {
      id: 'p123',
      title: 'Best React pattern in the world!',
      author: {
        id: 'a123',
        name: 'Francesco',
        email: 'name.surname@gmail.com',
      },
      comments: {
        'c123': {
          id: 'c123',
          body: 'Best article ever!',
        },
        'c124': {
          id: 'c124',
          body: 'Best article ever ever!',
        },
      }
    },
  }
}

// And so on, you get the point
```

The problem occurs if I wanted to create a page for the author's profile with a list of his posts.

To take an example with Redux selectors, we could retrieve the data we need in this way:

```javascript
// This returns an array of posts
const getPostsByAuthor = authorId => state => (
  Object.values(state.posts).filter(post => post.author.id === authorId)
)

// And you'd call this selector like this:
const state = store.getState()
const postsByAuthor = getPostsByAuthor('a123')(state) // [...]
```

But it would be particularly inefficient to be able to get what we need: every time we should go through all the posts.

## A weighted structure

A weighted structure could be a 1:1 representation of the hypothetical tables within our relational DBs.

```javascript
const store = {
  posts: {
    'p123': {
      id: 'p123',
      title: 'Best React pattern in the world!',
      author: 'a123',
    },
  },
  author_posts: {
    'a123': ['p123'],
  },
  authors: {
    'a123': {
      id: 'a123',
      name: 'Francesco',
      email: 'name.surname@gmail.com',
    }
  },
  post_comments: {
    'p123': ['c123', 'c124'],
  },
  comments: {
    'c123': {
      id: 'c123',
      body: 'Best article ever!',
      post: 'p123',
    },
    'c124': {
      id: 'c124',
      body: 'Best article ever ever!',
      post: 'p123',
    },
  },
}
```

In this case we removed the nesting problem. However, we added two new first level keys to our Redux store.

This approach is not totally wrong but, as our application grows, it may be difficult to manage all relationships efficiently.

It could be a usable approach if the amount of resources is limited. But it is also true that, if the amount of resources is limited, we may not really need Redux.

## An efficient structure

Following the recommendations of Firebase, we could save ourselves some first level keys:

```javascript
const store = {
  posts: {
    data: {
      'p123': {
        id: 'p123',
        title: 'Best React pattern in the world!',
        author: 'a123',
      },
    },
    comments: {
      'p123': ['c123', 'c124'],
    },
  },
  authors: {
    data: {
      'a123': {
        id: 'a123',
        name: 'Francesco',
        email: 'name.surname@gmail.com',
      },
    },
    posts: {
      'a123': ['p123'],
    },
  },
  comments: {
    data: {
      'c123': {
        id: 'c123',
        body: 'Best article ever!',
        post: 'p123',
      },
      'c124': {
        id: 'c124',
        body: 'Best article ever ever!',
        post: 'p123',
      },
    },
  },
}
```

Unlike Firebase, we are not going to nest relationships with "placeholders".

Instead, we organize our first-level keys as small second-level store containers.

Do you think of something similar thinking about the `reducers` and the `combineReducers` function? Same logic: we reduce our global object to the smallest representable portion.

## Bonus: how to structure selectors

After having structured our Redux store, the first question that could come to your mind could be: how do I get this data?

Here are some simple selectors.

```javascript
// Base data

const selectAuthors = state => Object.values(state.authors.data)
const selectAuthor = id => state => state.authors.data[id]

const selectPosts = state => Object.values(state.posts.data)
const selectPost = id => state => state.posts.data[id]

// Totally useless
const selectComments = state => Object.values(state.comments.data)
// Maybe useless
const selectComment = id => state => state.comments.data[id]

// Relations

const selectAuthorPosts = authorId => state => {
  const authorPosts = state.authors.posts[authorId] || []
  return authorPosts.map(postId => selectPost(postId)(state))
}

const selectPostComments = postId => state => {
  const postComments = state.posts.comments[postId] || []
  return postComments.map(commentId => selectComment(commentId)(state))
}
```

## Conclusion

Now you could structure a Redux store to save relational data. It could be overkill in some cases but it will come in handy to handle more complex applications.

Leave a 🦄 if you liked the post!