The BelongsTo Association
The BelongsTo
association is the association all other associations are based on. It's the simplest form of
association, and is meant to be used as a way to add a foreign key to a model.
We recommend reading the guides on HasOne
and HasMany
before reading this guide.
Defining a BelongsTo Association
The BelongsTo
association is used on the opposite side of where you would use a HasOne
or HasMany
association.
It is capable of creating both One-To-One and One-To-Many relationships.
For instance, here is how you would create the association we described in the HasMany
guide,
using a BelongsTo
association:
import {
Model,
DataTypes,
InferAttributes,
InferCreationAttributes,
CreationOptional,
NonAttribute,
} from '@sequelize/core';
import {
PrimaryKey,
Attribute,
AutoIncrement,
NotNull,
BelongsTo,
} from '@sequelize/core/decorators-legacy';
class Post extends Model<InferAttributes<Post>, InferCreationAttributes<Post>> {
@Attribute(DataTypes.INTEGER)
@AutoIncrement
@PrimaryKey
declare id: CreationOptional<number>;
}
class Comment extends Model<InferAttributes<Comment>, InferCreationAttributes<Comment>> {
@Attribute(DataTypes.INTEGER)
@AutoIncrement
@PrimaryKey
declare id: CreationOptional<number>;
@BelongsTo(() => Post, 'postId')
declare post?: NonAttribute<Post>;
// This is the foreign key
@Attribute(DataTypes.INTEGER)
@NotNull
declare postId: number;
}
And here is how you would create the association we described in the HasOne
guide:
import {
Model,
DataTypes,
InferAttributes,
InferCreationAttributes,
CreationOptional,
NonAttribute,
} from '@sequelize/core';
import {
PrimaryKey,
Attribute,
AutoIncrement,
NotNull,
HasOne,
BelongsTo,
} from '@sequelize/core/decorators-legacy';
class Person extends Model<InferAttributes<Person>, InferCreationAttributes<Person>> {
@Attribute(DataTypes.INTEGER)
@AutoIncrement
@PrimaryKey
declare id: CreationOptional<number>;
}
class DrivingLicense extends Model<
InferAttributes<DrivingLicense>,
InferCreationAttributes<DrivingLicense>
> {
@Attribute(DataTypes.INTEGER)
@AutoIncrement
@PrimaryKey
declare id: CreationOptional<number>;
@BelongsTo(() => Person, /* foreign key */ 'ownerId')
declare owner?: NonAttribute<Person>;
// This is the foreign key
@Attribute(DataTypes.INTEGER)
@NotNull
declare ownerId: number;
}
Inverse Association
Unlike the other 3 associations, BelongsTo
does not automatically create the inverse association, because it does
not know whether it should be a HasOne
or a HasMany
association.
You can configure the inverse association by using the inverse
option:
class Post extends Model<InferAttributes<Post>, InferCreationAttributes<Post>> {
@Attribute(DataTypes.INTEGER)
@AutoIncrement
@PrimaryKey
declare id: CreationOptional<number>;
/** Declared by {@link Comment#post} */
declare comments?: Comment[];
}
class Comment extends Model<InferAttributes<Comment>, InferCreationAttributes<Comment>> {
@Attribute(DataTypes.INTEGER)
@AutoIncrement
@PrimaryKey
declare id: CreationOptional<number>;
@BelongsTo(() => Post, {
foreignKey: 'postId',
inverse: {
as: 'comments',
// Either 'hasOne' or 'hasMany'
type: 'hasMany',
},
})
declare post?: NonAttribute<Post>;
// This is the foreign key
@Attribute(DataTypes.INTEGER)
@NotNull
declare postId: number;
}
Association Methods
The BelongsTo
association adds the following methods to the model it is defined on:
Association Getter (getX
)
The getter method is used to retrieve the associated model. It is always named get<AssociationName>
.
import { BelongsToGetAssociationMixin } from '@sequelize/core';
class Comment extends Model {
@BelongsTo(() => Post, 'postId')
declare post?: NonAttribute<Post>;
declare getPost: BelongsToGetAssociationMixin<Post>;
}
const comment = await Comment.findByPk(1);
const post = await comment.getPost();
Association Setter (setX
)
The setter method is used to associate a model with another model. It is always named set<AssociationName>
.
It is equivalent to setting the foreign key directly, then calling save
.
import { BelongsToSetAssociationMixin } from '@sequelize/core';
class Comment extends Model {
@BelongsTo(() => Post, 'postId')
declare post?: NonAttribute<Post>;
declare setPost: BelongsToSetAssociationMixin<Post, /* Foreign Key Type */ Comment['postId']>;
}
const comment = await Comment.findByPk(1);
const post = await Post.findByPk(1);
await comment.setPost(post);
// Or, if you already have the foreign key
await comment.setPost(1);
It is also possible to delay the call to save
by setting the save
option to false
, however this is not very useful,
as it is equivalent to setting the foreign key directly, but using a (pointlessly) asynchronous method.
await comment.setPost(post, { save: false });
await comment.save();
Association Creator (createX
)
The creator method is used to create a new associated model. It is always named create<AssociationName>
.
It is equivalent to creating a new model, then setting the foreign key, then calling save
.
import { BelongsToCreateAssociationMixin } from '@sequelize/core';
class Comment extends Model {
@BelongsTo(() => Post, 'postId')
declare post?: NonAttribute<Post>;
declare createPost: BelongsToCreateAssociationMixin<Post>;
}
const comment = await Comment.create({ content: 'This is a comment' });
const post = await comment.createPost({
title: 'New Post',
content: 'This is a new post',
});
Using this method is discouraged, as it is less efficient than creating the associated model first, then creating or updating the current model.
The following code is more efficient:
const post = await Post.create({
title: 'New Post',
content: 'This is a new post',
});
const comment = await Comment.create({
content: 'This is a comment',
postId: post.id,
});
Or, if you have defined the inverse association, this is just as efficient:
const post = await Post.create({
title: 'New Post',
content: 'This is a new post',
});
const comment = await post.createComment({
content: 'This is a comment',
});
Foreign Key targets (targetKey
)
By default, Sequelize will use the primary key of the target model as the attribute the foreign key references.
You can customize this by using the targetKey
option.
class Comment extends Model {
declare id: CreationOptional<number>;
@BelongsTo(() => Post, {
foreignKey: 'postId',
// The foreign key will reference the 'id' attribute of the Post model
targetKey: 'id',
})
declare post?: NonAttribute<Post>;
}