Sequelize Association Cheatsheet
Updated for Sequelize v2/3/4/5
Generally I think the problems are that we are confused about what tables created, and what methods are gained by associations.
Note: Defining foreignKey or cross table name are optional. Sequelize automatically creates it, but defining it allows coders to read the models and find out what the foreign keys/cross table names are, instead of guessing or needing to access the database.
TLDR;
O:O
// foreign key has to be defined on both sides.
Parent.hasOne(Child, {foreignKey: 'Parent_parentId'})
// "Parent_parentId" column will exist in the "belongsTo" table.
Child.belongsTo(Parent, {foreignKey: 'Parent_parentId'})
O:M
Parent.hasMany(Child, {foreignKey: 'Parent_parentId'})
Child.belongsTo(Parent, {foreignKey: 'Parent_parentId'})
N:M
Parent.belongsToMany(
Child,
{
// this can be string (model name) or a Sequelize Model Object Class
// through is compulsory since v2
through: 'Parent_Child',
// GOTCHA
// note that this is the Parent's Id, not Child.
foreignKey: 'Parent_parentId'
}
)
/*
The above reads:
"Parents" belongs to many "Children", and is recorded in the "Parent_child" table, using "Parents"'s ID.
*/
Child.belongsToMany(
Parent,
{
through: 'Parent_Child',
// GOTCHA
// note that this is the Child's Id, not Parent.
foreignKey: 'Child_childId'
}
)
Why the verbose "Parent_parentId" and not just "parentId"? This is to make it obvious that it's a foreign key that belonged to "Parent". In most cases it's okay to just use the more succinct "parentId".*
Associations gives you 2 functionality: (1) Eager loading and (2) DAO Methods:
1. Include (Eager loading)
DB.Parent.findOne({
where: { id: 1 },
include: [ DB.Child ]
}).then(parent => {
// you should get `parent.Child` as an array of children.
})
2. Methods gained by hasOne(), hasMany() and belongsTo()/belongsToMany()
Associations give the Data Access Object (DAO) methods:
hasOne():
In setting a Parent.hasOne(Child)
, methods available to parent
DAO instance:
DB.Parent.findOne({ where: { id: 1 } }).then(parent => {
// `parent` is the DAO
// you can use any of the methods below:
parent.getChild
parent.setChild
parent.addChild
parent.createChild
parent.removeChild
parent.hasChild
})
hasMany():
In setting a Parent.hasMany(Child)
, methods available to parent
DAO instance:
parent.getChildren,
parent.setChildren,
parent.addChild,
parent.addChildren,
parent.createChild,
parent.removeChild,
parent.hasChild,
parent.hasChildren,
belongsTo()/belongsToMany:
In setting a Child.belongsTo(Parent)
, methods available to child
DAO instance:
child.getParent,
child.setParent,
child.createParent,
//belongsToMany
child.getParents,
child.setParents,
child.createParents,
You can also have multiple relationships
Natural Parents/Children
// a parent can have many children
Parent.belongsToMany(Child, {
as: 'Natural',
through: 'Parent_Child',
foreignKey: 'Parent_parentId'
})
// a child must at least have 2 parents (natural mother and father)
Child.belongsToMany(Parent, {
as: 'Natural',
through: 'Parent_Child',
foreignKey: 'Child_childId'
})
Foster Parents/Children
Parent.belongsToMany(Child, {
as: 'Foster',
through: 'Parent_Child',
foreignKey: 'Parent_parentId'
})
Child.belongsToMany(Parent, {
as: 'Foster',
through: 'Parent_Child',
foreignKey: 'Child_childId'
});
The above will create the Parent_Child
cross table, with NaturalId
and FosterId
.