Skip to content

Instantly share code, notes, and snippets.

@elliette
Last active October 31, 2023 16:03
Show Gist options
  • Star 54 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save elliette/20ddc4e827efd9d62bc98752e7a62610 to your computer and use it in GitHub Desktop.
Save elliette/20ddc4e827efd9d62bc98752e7a62610 to your computer and use it in GitHub Desktop.
Describing `belongsToMany` and `hasMany` methods in Sequelize

Defining Many-to-Many Associations in Sequelize

Reference: Sequelize docs on association

Let’s say we have two models: Films and Festivals

We know that a film can be shown at many film festivals and that, conversely, a festival can show many films. This is what is known as a many-to-many relationship.

Knowing this, we can set up our associations:

1. A film can be shown at many festivals - belongsToMany

If a film can be shown at many festivals, we can say that it belongs to many festivals. In Sequelize, we can write this association as follows:

Film.belongsToMany(Festival, {through: FestivalFilm} );

When we use the method belongsToMany, Sequelize will create a join table for us holding the foreign keys of the source and target models that we specified. So, in our example above, Sequelize creates a join table for the source (Film) and target (Festival). As we specified with the option through, the join table is named FestivalFilm, and it holds the foreign keys filmId and festivalId.

Furthermore, by using the method belongsToMany , Sequelize will create a series of methods for us that we can use on any instance of the source model (remember, the source model is the model before the dot).

So in our example above, we can now use the methods:

  • film.getFestival
  • film.setFestival
  • film.addFestival
  • film.addFestivals

Here is an example where we are using the method setFestival to associate a festival with a film:

app.post('/filmFestival', function(req, res, next) {
        Promise.all([
            Film.create(req.body.film),
            Festival.create(req.body.festival)
        ])
        .spread(function(film, festival) {
                return film.setFestival(associatedFestival); // here we are using the method setFestival 
        })
        .then(function(filmWithAssociatedFestival){
                res.send(filmWithAssociatedFestival); 
        })
        .catch(next)
}); 

2. A festival can show many films - hasMany

Conversely, we could choose instead to say that since a festival can show many films, it has many films. In Sequelize, we can write this association as follows:

Festival.hasMany(Films)

When we use the method hasMany, Sequelize will add a foreign key for our source to our target model. So, in our example above, Sequelize will add the foreign key festival_id to the Film model.

Furthermore, by using the method hasMany, Sequelize will create a series of methods for us that we can use on any instance of the source model (remember, the source model is the model before the dot).

So in our example above, we can now use the methods:

  • festival.getFilms
  • festival.setFilms

Some important addendums:

  1. You should not use use belongsToMany and hasMany together, because they do fundamentally different things in regards to SQL. In our film-festival example, you could say a Festival.hasMany(Films) or that a Film.belongsToMany(Festival, {through: FestivalFilm} ) but you should never write both.

  2. You can, however, declare 'symmetric associations' like so:

    Film.belongsToMany(Festival, { through: 'film_festival' })

    Festival.belongsToMany(Film, { through: 'film_festival' })

    or

    Film.hasMany(Review)

    Review.belongsTo(Film)

    Although the "redundant" association does nothing new vis-à-vis the SQL tables, it does mean that the other instance gets the "magic" methods.

  3. Finally, be cognizant of the difference between many-to-many and many-to-one relationships. Let’s imagine we have have a third model that represents film reviews. We could say that a film has many reviews, but not that a review belongs to many films. A review belongs to only one film. Therefore, reviews and films are a many-to-one relationship, not a many-to-many relationship.

@ajLapid718
Copy link

Very informative! Much appreciated!

@JoseCrz
Copy link

JoseCrz commented Nov 26, 2018

Thanks for the info, really help me out!

@parkernilson
Copy link

This is really, really great. Thank you very much.

@kingsleyudenewu
Copy link

Nice article, but what if you want to update the belongsToMany relationship like updating a festival and also a film.

@TidyIQ
Copy link

TidyIQ commented May 24, 2019

I'm a bit confused. The sequelize documentation says that HasMany is a one-to-many relation. whereas you have it here as a many-to-many. Which is correct?

My use case is that I have users and companies. This is a many-to-many association. A user can have/belong to many companies and companies can have/belong to many users. I'm not sure which approach to use. Any advice?

@ibadeeCodes
Copy link

Can we declare 'symmetric associations' like this too??

Film.hasMany(Festival, { through: 'film_festival' })

Festival.hasMany(Film, { through: 'film_festival' })

@ibadeeCodes
Copy link

I'm a bit confused. The sequelize documentation says that HasMany is a one-to-many relation. whereas you have it here as a many-to-many. Which is correct?

My use case is that I have users and companies. This is a many-to-many association. A user can have/belong to many companies and companies can have/belong to many users. I'm not sure which approach to use. Any advice?

Im also confused in it..

@danoseun
Copy link

@elliette Can you please help out with the questions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment