Skip to content

Instantly share code, notes, and snippets.

@AloofBuddha
Last active February 27, 2024 08:25
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • 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!

@iFwu
Copy link

iFwu commented Aug 3, 2017

The "hasOne" part seems different from the official guide.

const User = sequelize.define('user', {/* ... */})
const Project = sequelize.define('project', {/* ... */})
// One-way associations
Project.hasOne(User)
/*
  In this example hasOne will add an attribute projectId to the User model!
  Furthermore, Project.prototype will gain the methods getUser and setUser according
  to the first parameter passed to define. If you have underscore style
  enabled, the added attribute will be project_id instead of projectId.

  The foreign key will be placed on the users table.

  You can also define the foreign key, e.g. if you already have an existing
  database and want to work on it:
*/

I tried and found the official tutorial may be 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