# Objection Relationships
# Introduction
Database tables are often related to one another. A relationship defines how two entities relate to each other. In a relational database, this is represented by a foreign key constraint.
One To One (BelongsToOneRelation)
One To Many (HasManyRelation)
Many To Many (ManyToManyRelation)
While relations are usually created between the primary key of one table and a foreign key reference of another table, ExpressWebJs has no such limitations. You can create relationship using any two columns (or any sets of columns). You can even create relation using values nested deep inside json columns.
# One To One (BelongsToOneRelation)
BelongsToOneRelation
: Use this relation when the source model has the foreign key
import { Model } from "Elucidate/Database/Model";
export class ProfileModel extends Model {
static tableName = "profiles";
id!: number;
gender!: string;
photo!: string;
user_id!: number;
}
import { Model } from "Elucidate/Database/Model";
import { ProfileModel } from "App/Model/ProfileModel";
export class UserModel extends Model {
static tableName = "users";
id!: number;
first_name!: string;
last_name!: string;
phone_number!: string;
email!: string;
password!: string;
static relationMappings = {
profile: {
relation: Model.BelongsToOneRelation,
modelClass: ProfileModel,
join: {
from: "users.id",
to: "profiles.user_id",
},
},
};
}
Or you can use the belongsTo
method.
import { Model } from "Elucidate/Database/Model";
export class UserModel extends Model {
static tableName = "users";
id!: number;
first_name!: string;
last_name!: string;
phone_number!: string;
email!: string;
password!: string;
static relationMappings() {
return {
profile: this.belongsTo("App/Model/ProfileModel", { foreign_key: "user_id" }),
};
}
}
# One To Many (HasManyRelation)
HasManyRelation
: Use this relation when the related model has the foreign key
import { Model } from "Elucidate/Database/Model";
import { CarModel } from "App/Model/CarModel";
export class PersonModel extends Model {
static tableName = "persons";
static relationMappings = {
cars: {
relation: Model.HasManyRelation,
modelClass: CarModel,
join: {
from: "persons.id",
to: "cars.owner_id",
},
},
};
}
Or you can use the hasMany
method.
import { Model } from "Elucidate/Database/Model";
export class PersonModel extends Model {
static tableName = "persons";
static relationMappings() {
return {
cars: this.hasMany("App/Model/CarModel", { foreign_key: "owner_id" }),
};
}
}
HasOneRelation
: Just like HasManyRelation
but for one related row
import { Model } from "Elucidate/Database/Model";
import { CarModel } from "App/Model/CarModel";
export class PersonModel extends Model {
static tableName = "persons";
static relationMappings = {
car: {
relation: Model.HasOneRelation,
modelClass: CarModel,
join: {
from: "persons.id",
to: "cars.owner_id",
},
},
};
}
Or you can use the hasOne
method.
import { Model } from "Elucidate/Database/Model";
export class PersonModel extends Model {
static tableName = "persons";
static relationMappings() {
return {
cars: this.hasOne("App/Model/CarModel", { foreign_key: "owner_id" }),
};
}
}
# Many To Many (ManyToManyRelation)
ManyToManyRelation
: Use this relation when the model is related to a list of other models through a join table
import { Model } from "Elucidate/Database/Model";
import { MovieModel } from "App/Model/MovieModel";
export class PersonModel extends Model {
static tableName = "persons";
static relationMappings = {
movies: {
relation: Model.ManyToManyRelation,
modelClass: MovieModel,
join: {
from: "persons.id",
through: {
// persons_movies is the join table.
from: "persons_movies.personId",
to: "persons_movies.movieId",
},
to: "movies.id",
},
},
};
}
Or you can use the hasManyThrough
method.
import { Model } from "Elucidate/Database/Model";
export class PersonModel extends Model {
static tableName = "persons";
static relationMappings() {
return {
movie: this.hasManyThrough("App/Model/MovieModel", "App/Model/PersonsMoviesModel", {
join_parient_foreign_key: "movie_id",
join_final_foreign_key: "person_id",
}),
};
}
}
HasOneThroughRelation
: Use this relation when the model is related to a single model through a join table
import { Model } from "Elucidate/Database/Model";
import MovieModel from "App/Model/MovieModel";
export class PersonModel extends Model {
static tableName = "persons";
static relationMappings = {
movies: {
relation: Model.HasOneThroughRelation,
modelClass: MovieModel,
join: {
from: "persons.id",
through: {
// persons_movies is the join table.
from: "persons_movies.personId",
to: "persons_movies.movieId",
},
to: "movies.id",
},
},
};
}
Or you can use the hasOneThrough
method.
import { Model } from "Elucidate/Database/Model";
export class PersonModel extends Model {
static tableName = "persons";
static relationMappings() {
return {
movie: this.hasOneThrough("App/Model/MovieModel", "App/Model/PersonsMoviesModel", {
join_parient_foreign_key: "movie_id",
join_final_foreign_key: "person_id",
}),
};
}
}
Visit ObjectionJs documentation site (opens new window) for more info.
# Add ons
There are other ways to handle Objection relationships in ExpressWebJs
Relationship mapping method now has a nice way of handling relationships with the new hasMany, belongsTo, hasOne, hasOneThrough, hasManyThrough
methods which also accepts addition options.
# hasManyThrough()
export class UserModel extends Model {
static tableName = "users";
id!: string;
name!: string;
email!: string;
password!: string;
static relationMappings() {
return {
carOwner: this.hasManyThrough("App/Model/Cars_model", "App/Model/CarOwners_model", {
join_final_foreign_key: "user_id",
join_parent_foreign_key: "car_id",
}),
};
}
}
# hasOneThrough()
export class UserModel extends Model {
static tableName = "users";
id!: string;
name!: string;
email!: string;
password!: string;
static relationMappings() {
return {
carOwner: this.hasOneThrough("App/Model/Cars_model", "App/Model/CarOwners_model", {
join_final_foreign_key: "user_id",
join_parent_foreign_key: "car_id",
}),
};
}
}
# hasOne()
export class UserModel extends Model {
static tableName = "users";
id!: string;
first_name!: string;
last_name!: string;
email!: string;
password!: string;
static relationMappings() {
return {
profile: this.hasOne("App/Model/Profile_model"),
};
}
}
# hasMany()
export class UserModel extends Model {
static tableName = "users";
id!: string;
first_name!: string;
last_name!: string;
email!: string;
password!: string;
static relationMappings() {
return {
profile: this.hasMany("App/Model/Cars_model"),
};
}
}
# Relation filters
You can also add some filters in your relationship mapping:
static relationMappings() {
return {
profile: this.hasMany("App/Model/Cars_model",{
filter: (builder) => {
builder.where("name", "Mercedes");
},
}),
};
}
# belongsTo()
export class Posts extends Model {
static tableName = "posts";
id!: string;
name!: string;
user_id!: string;
static relationMappings() {
return {
users: this.belongsTo("App/Model/Users_model"),
};
}
}