Many to Many
Many to Many Relationship
Many-to-many relations are slightly more complicated than hasOne
and hasMany
relationships. An example of a many-to-many relationship is a user that has many roles and those roles are also shared by other users in the application. For example, a user may be assigned the role of "Author" and "Editor"; however, those roles may also be assigned to other users as well. So, a user has many roles and a role has many users.
Collection structure
To define this relationship, three database collections are needed: users
, roles
, and roleUser
. The roleUser
collection is derived from the alphabetical order of the related model names and contains userId
and roleId
keys. This collection is used as an intermediate collection linking the users
and roles
.
Remember, since a role can belong to many users, we cannot simply place a userId
column on the roles
collection. This would mean that a role could only belong to a single user. In order to provide support for roles being assigned to multiple users, the roleUser
collection is needed. We can summarize the relationship's collection structure like so:
users
_id - ObjectId
name - string
roles
_id - ObjectId
name - string
roleUser
_id - ObjectId
userId - ObjectId
roleId - ObjectId
Model Structure
Many-to-many relationships are defined by writing a method that returns the result of the belongsToMany
method. For example, let's define a roles
method on our User
model. The first argument passed to this method is the name of the related model class:
import { Mongoloquent } from "mongoloquent";
import Role from "./yourPath/Role";
import RoleUser from "./yourPath/RoleUser";
class User extends Mongoloquent {
static collection = "users";
static roles() {
return this.belongsToMany(Role, RoleUser, "userId", "roleId");
}
}
Once the relationship is defined, you may access the user's roles using the roles
dynamic relationship property:
import User from "./yourPath/User";
const user = await User.with("roles").find("65ab7e3d05d58a1ad246ee87");
// your relationship data can accessed in the data property
console.log(user.data);
Defining the Inverse of the Relationship
To define the "inverse" of a many-to-many relationship, you should define a method on the related model which also returns the result of the belongsToMany method. To complete our user / role example, let's define the users method on the Role model:
import { Mongoloquent } from "mongoloquent";
import User from "./yourPath/User";
import RoleUser from "./yourPath/RoleUser";
class Role extends Mongoloquent {
static collection = "roles";
static users() {
return this.belongsToMany(User, RoleUser, "roleId", "userId");
}
}
Select and Exclude Related Model Keys
Monggoloquent can also select
or exclude
certain related model keys
import User from "./yourPath/User";
// with select keys
await User.with("roles", {
select: ["name"],
}).find("65ab7e3d05d58a1ad246ee87");
// with exclude keys
await User.with("roles", {
exclude: ["name"],
}).find("65ab7e3d05d58a1ad246ee87");
Support us
Mongoloquent is an MIT-licensed open source project. It can grow thanks to the support by these awesome people. If you'd like to join them, please read more here.
Sponsors
_