Understanding Sequelize Associations: Part 2: One to Many (1:n) mapping

Siddharth Lakhara
6 min readDec 31, 2019

--

Photo by Taylor Vick on Unsplash

This is 2nd part of 3 part blog series in which I explain sequelize associations by creating a CRUD app. The description and links of each part is as follows:

This blog assumes that you have basic understanding of NodeJs, Databases and Sequelize.

Source repo for this blog

Complete repo link

1. What are we going to do in this blog

In this blog, I will explain 1:n mapping in sequelize by creating a CRUD app. We will be working on the same app we used in the last blog. The tech stack of the app is as follows:

In the last blog, we created two tables: users and userDetails. In this part, we will create an additional table called posts. This table will have 1:n relation with our users table. The foreign key will be userId which belongs to users table. The updated ER diagram is as follows:

Updated ER Diagram

2. Generate Models

We have already created users and usersDetails in the last post. Now, we will create posts model. Similar to the last time, we will first create our models using sequelize-cli, then modify the generated models according to our associations

2.1 Create models using sequelize-cli

Run the following command to create our new model posts. This command will also generate relevant migrations.

node_modules/.bin/sequelize model:generate posts --attributes userId:integer,title:string

2.2 Modify models for association

Now that we have our migrations and models generated by sequelize, we will modify them according to our associations. Find the migration titled like: create-posts and modify the userId attribute to match as follows:

userId: {
type: Sequelize.INTEGER,
references: { model: 'users', key: 'id' },
onDelete: 'CASCADE',
}

Now, find the model posts and add associations as follows:

posts.associate = (models) => {
posts.belongsTo(models.users, {
foreignKey: 'userId',
as: 'users'
});
};

This code can be read like: the model posts has a foreign key userId, which belongsTo the model users.

Now that we have modified posts model. We now need to modify our users model, in order to associate users model with posts. Since, in this case, one user can have multiple posts, we will use hasMany relation on users model to reflect that. So, next, find the model users and modify the associations as follows:

users.associate = function (models) {
users.hasOne(models.userDetails, {
foreignKey: 'userId',
as: 'userDetails',
onDelete: 'CASCADE'
});
// we are adding the following now
users.hasMany(models.posts, {
foreignKey: 'userId',
as: 'posts'
});
};

Notice that, users was previously associated with usersDetails only. Now users is associated with two models simultaneously i.e. usersDetails and posts.

2.3 Side note: what are hasOne, belongsTo, hasMany, belongsToMany ?

I explained this in previous part too, but in order to keep the blog complete, I’m again explaining them

All the four keywords are used to define associations in our sequelize model. One way to differentiate them is to consider the following points:

1. Whenever the foreign key is defined on the source model (the model for which we are writing this association), use belongsTo or belongsToMany

2. If the foreign key is defined on the target model (the model with which we will be associating), use hasOne or hasMany

3. If we are considering multiple mappings (1:n, or n:m), then, we have to use hasMany or belongsToMany

For eg, in this scenario, userDetails has the foreign key userId. Hence, I have used hasOne constraint. Read like: model users has one key defined on the model userDetails with name key as userId.

Similarly, if we had defined a belongsTo relation on userDetails, this would have been as follows:

userDetails.associate = function (models) {
userDetails.belongsTo(models.users, {
foreignKey: 'userId',
as: 'users'
});
};

This can be read like: model userDetails has a foreign key which belongs to the model users. The foreign key is userId.

2.4 Run migrations

Now that we have all our models and migrations ready. We will run the migrations, so that our corresponding tables are replicated in our database. Run the following command:

node_modules/.bin/sequelize db:migrate

Sequelize will only run new migrations. Hence, migrations of users and usersDetails won’t run. We will now be able to see foreign key constraints defined on our posts table:

Constraints on posts table

3. Creating CRUD app

We will now move on by modifying our CRUD app, we built in the last post. We will add new post API for working with posts table. Also, we will have to modify our existing users API, to reflect new changes. The complete file can be found here: Users API, Posts API

3.1 Create API

Our create API for table posts will be a POST API. This API will expect post title and userId. Sequelize will handle the case when the provided userId doesn’t exist. So essentially, we don’t need to handle that. The code looks like as follows:

Create posts

Similarly, we need to modify our users API. We now need to pass posts details along with users details. Since, one user can have multiple posts, we need to provide posts details as an array of object. Each object contains details of a post. A sample payload will look as follows:

{
"name": "ABCD",
"userName": "abcd.abcd",
"mobileNum": "1234567890",
"address": "Earth",
"posts": [{
"title": "some post title 1"
}, {
"title": "some post title 2"
}, {
"title": "some post title 3"
}, {
"title": "some post title 4"
}]
}

The corresponding changes in our create users API is as follows:

Git diff of create users API

3.2 Read API

Following is code for reading posts:

Read posts

We need to modify our users API, so that it now includes relevant records from posts table too. The changes will be as follows:

Git diff for read users API

3.3 Update API

API for updating posts can be written as shown below:

update posts

For update users API, our function now expects an array of posts that needs to be updated. Since, sequelize doesn’t provide any methods to update records with associations. Hence, we are updating all tables one by one. For updating post, we will consider each post separately and update it. The changes look as follows:

Git diff of update users API

In case you want to see the full file, find it here

3.4 Delete API

API for deleting posts can be written as shown follows:

delete posts

There is no modification required in our delete users API.

Wrapping Up

In this blog, I showed how you can create 1:n Mapping and utilise sequelize functions to do basic tasks. In the next blog, I will write about Many-to-Many (n:m) mapping. Link.

If you have any questions, please comment them. I will try to answer them as soon as possible

Source repo for this blog: link

Complete repo:

If you like this post, clap this post to show your appreciation. More number of claps motivates me to keep writing such posts.

Follow me on Github and Medium

--

--

Siddharth Lakhara
Siddharth Lakhara

Written by Siddharth Lakhara

Full stack developer @Cisco, Ex-@McKinsey | Bibliophile | Coder by heart | Opinions are mine

No responses yet