
Join the Conversation!
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.
In this lesson, we will learn how to create many-to-many references in Mongoose. This differs slightly from the one-to-many references we have seen before.
In a many-to-many relationship, each record in the first collection can be associated with multiple records in the second collection, and each record in the second collection can be associated with multiple records in the first collection.
So let's imagine a movie and actor database.
A movie can have many actors, and an actor can be in many movies. This is a many-to-many relationship.
We might want the ability to query a movie and see all the actors in it, or query an actor and see all the movies they have been in. This kind of relationship is not possible with a one-to-many relationship. We need a relationship.
To create a many-to-many relationship in Mongoose, we can use one of two methods:
In this method, we add an array of references to the other collection in each document.
For example, in our movie and actor database, we would add an array of actor references to each movie document and an array of movie references to each actor document.
Here is an example of how we might do this:
//
// Movie Schema
//
const movieSchema = new mongoose.Schema({
title: String,
actors: [{ type: mongoose.Schema.Types.ObjectId, ref: "Actor" }],
});
const Movie = mongoose.model("Movie", movieSchema);
//
// Actor Schema
//
const actorSchema = new mongoose.Schema({
name: String,
movies: [{ type: mongoose.Schema.Types.ObjectId, ref: "Movie" }],
});
const Actor = mongoose.model("Actor", actorSchema);
In this example, we have two schemas: one for movies and one for actors. Each schema has an array of references to the other collection.
To query a many-to-many relationship, we can use the populate method in Mongoose.
For example, to get all the actors in a movie, we can do the following:
//
// Get all the actors in a movie
//
const movieWithActors = await Movie.findById(movieId).populate("actors");
console.log(movieWithActors);
const actorWithMovies = await Actor.findById(actorId).populate("movies");
console.log(actorWithMovies);
//
// movieWithActors:
{
_id: 'movieId1',
title: 'Movie Title',
actors: [
{ _id: 'actorId1', name: 'Actor 1' },
{ _id: 'actorId2', name: 'Actor 2' }
]
}
//
// actorWithMovies:
{
_id: 'actorId1',
name: 'Actor Name',
movies: [
{ _id: 'movieId1', title: 'Movie 1' },
{ _id: 'movieId2', title: 'Movie 2' }
]
}
Because of the many-to-many relationship, we can have multiple actors in a movie and multiple movies for an actor, and query both sides of the relationship.
The main advantage of this method is that it is simple and easy to understand. However, you need to make sure you keep both arrays in sync. This means that if you add an actor to a movie, you also need to add the movie to the actor. This can be error-prone and lead to inconsistencies in the data.
You lack a single "source of truth" for the relationship, which can make it harder to query and maintain the data.
In this method, we create a new collection to store the relationships between movies and actors. This collection will have two fields: one for the movie reference and one for the actor reference.
This is a classic way to model many-to-many relationships in databases.
Here is an example of how we might do this:
//
// Movie Schema
//
const movieSchema = new mongoose.Schema({
title: String,
});
const Movie = mongoose.model("Movie", movieSchema);
//
// Actor Schema
//
const actorSchema = new mongoose.Schema({
name: String,
});
const Actor = mongoose.model("Actor", actorSchema);
//
// Relationship Schema
//
const actorMoviesSchema = new mongoose.Schema({
movie: { type: mongoose.Schema.Types.ObjectId, ref: "Movie" },
actor: { type: mongoose.Schema.Types.ObjectId, ref: "Actor" },
});
const ActorMovies = mongoose.model("ActorMovies", actorMoviesSchema);
In this example, we have three schemas:
To query a many-to-many relationship using this method, we can use the populate method in Mongoose.
For example, to get all the actors in a movie, we can do the following:
//
// Get all the actors in a movie
//
const actorsInMovie = await ActorMovies.find({ movie: movieId }).populate(
"actor",
);
console.log(actorsInMovie);
const moviesForActor = await ActorMovies.find({ actor: actorId }).populate(
"movie",
);
console.log(moviesForActor);
//
// actorsInMovie:
[
{
_id: "actorMovieId1",
movie: "movieId1",
actor: { _id: "actorId1", name: "Actor 1" },
},
{
_id: "actorMovieId2",
movie: "movieId1",
actor: { _id: "actorId2", name: "Actor 2" },
},
][
//
// moviesForActor:
({
_id: "actorMovieId1",
actor: "actorId1",
movie: { _id: "movieId1", title: "Movie 1" },
},
{
_id: "actorMovieId2",
actor: "actorId1",
movie: { _id: "movieId2", title: "Movie 2" },
})
];
In this method, we have a single "source of truth" for the relationship between movies and actors. This makes it easier to query and maintain the data. However, it requires an additional collection to store the relationships, which can add complexity to the database schema.
In this lesson, we learned how to create many-to-many relationships in Mongoose using two different methods: adding arrays of references to both collections and creating a new collection to store the relationships.
"Please login to view comments"
Subscribing gives you access to the comments so you can share your ideas, ask questions, and connect with others.