Skip to content

Instantly share code, notes, and snippets.

@AloofBuddha
Last active February 27, 2024 08:25
Show Gist options
  • Save AloofBuddha/22d887a6ee2bdf5aec2df3e4b499497e to your computer and use it in GitHub Desktop.
Save AloofBuddha/22d887a6ee2bdf5aec2df3e4b499497e to your computer and use it in GitHub Desktop.
Sequelize Relationships: hasOne vs belongsTo

Sequelize Relationships: hasOne vs belongsTo

Docs

Intro

First, what's the same - they both define a One-to-One relationship: an association between exactly two models connected by a single foreign key. The difference between them is in which model is the source and which is the target, and what additional helper functions are provided when the relationship is defined.

They are conversely related:

  • modelA.belongsTo(modelB) - modelA is the source, modelB is the target
  • modelB.hasOne(modelA) - modelB is the source, modelA is the target

Here's some examples:

Defining Models

This is common to both

Sequelize

var Artist = this.sequelize.define('artist', { name: Sequelize.STRING })
var Band   = this.sequelize.define('band', { name: Sequelize.STRING });

PostgreSQL

artists
=======
id  |      name     
---------------------
1   |  "Big Boi"
2   |  "Andre 3000"
3   |  "Jack White"
4   |  "Meg White" 


bands
=====
id  |             name          
---------------------------------
1   |    "Outkast"
2   |    "The White Stripes"

belongsTo

Artist.belongsTo(Band) will create a one-to-one association with Artist as the source and Band as the target. This means the foreign key for Band will be added to the Artist model.

Note how many artists can belong to the same band!

Sequelize

var Artist = this.sequelize.define('artist', { name: Sequelize.STRING })
var Band   = this.sequelize.define('band', { name: Sequelize.STRING });

Artist.belongsTo(Band); 
// adds 'bandId' field to Artist model
// adds Artist instance methods 'getBand', 'setBand', and 'createBand'

PostgreSQL

artists
=======
id  |      name         |  bandId
---------------------------------
1   |  "Big Boi"        | 1
2   |  "Andre 3000"     | 1
3   |  "Jack White"     | 1
4   |  "Meg White"      | 2


bands
=====
id  |             name          
---------------------------------
1   |    "Outkast"
2   |    "The White Stripes"

Example

Artist.findById(1)
  .then(function (artist) {
    console.log(artist.name);    // "Big Boi"
    console.log(artist.bandId); // 1
    
    return artist.getBand();    // like all database queries, returns a Promise
  })
  .then(function (band) {
    console.log(band);         // "Outkast" 
  });

hasOne

Band.hasOne(Artist) will create a one-to-one association with Band as the source and Artist as the target. This means the foreign key for Artist will be added to the Band model (inverse of belongsTo).

Note how a band can only have one lead!

Sequelize

var Artist = this.sequelize.define('artist', { name: Sequelize.STRING })
var Band   = this.sequelize.define('band', { name: Sequelize.STRING });

Band.hasOne(Artist, { as: "lead" }); 
// adds 'leadId' field to Band model
// adds Band instance methods 'getLead', 'setLead', and 'createLead'

PostgreSQL

artists
=======
id  |      name         
--------------------
1   |  "Big Boi"        
2   |  "Andre 3000"     
3   |  "Jack White"     
4   |  "Meg White"      


bands
=====
id  |             name         |  leadId
-------------------------------------------
1   |    "Outkast"             | 2
2   |    "The White Stripes"   | 3

Example

Band.findById(1)
  .then(function (band) {
    console.log(band.name);    // "Outkast"
    console.log(band.leadId); // 2
    
    return band.getLead();    // like all database queries, returns a Promise
  })
  .then(function (artist) {
    console.log(artist);         // "Andre 3000" 
  });

Note: this is not meant to be a statement on who the 'lead' of Outkast is: Andre 3000 and Big Boi are both talented in their own right!

@eserdinyo
Copy link

Hi. I tried same code but i'm getting an error like this: TypeError: Artist.belongsTo is not a function

here is my code:
const Sequelize = require('sequelize');
const sequelize = new Sequelize('senior', 'root', '12345678', {
host: 'localhost',
dialect: 'mysql',
freezeTableName: true,
operatorsAliases: false
});

var Artist = sequelize.define('artist', { name: Sequelize.STRING }).sync({ force: true })
var Band = sequelize.define('band', { name: Sequelize.STRING }).sync({ force: true });
Artist.belongsTo(Band);

@sagarrajak
Copy link

Hey It seems you are wrong about hasOne part according to documentation
`Having Player as the source and Team as the target

Player.belongsTo(Team);
//Or
Player.hasOne(Team);
Having Team as the source and Player as the target

Team.belongsTo(Player);
//Or
Team.hasOne(Player);
HasOne and BelongsTo insert the association key in different models from each other. HasOne inserts the association key in target model whereas BelongsTo inserts the association key in the source model.`

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