Relationships in MongoDB describe how documents in one collection are associated with documents in another collection. MongoDB supports embedded documents and references to represent these relationships.
A relationship connects related information. For example, a student may enroll in several courses, a customer may place multiple orders, or a department may have several employees.
Common examples include:
MongoDB does not automatically enforce relational foreign-key constraints. Applications must manage references and related data appropriately.
| Relationship | Meaning | Example |
|---|---|---|
| One-to-One | One record relates to one other record. | Student and profile |
| One-to-Many | One record relates to many records. | Student and fee payments |
| Many-to-Many | Many records relate to many others. | Students and courses |
A one-to-one relationship means one document is associated with one related document. When related information is small and commonly accessed together, embedding it may be convenient.
db.relationship_students.insertOne({
student_id: 101,
name: "Rahul",
profile: {
dateOfBirth: "2005-04-15",
city: "Aurangabad",
state: "Bihar"
}
})
Retrieve the student's profile:
db.relationship_students.find(
{ student_id: 101 },
{ _id: 0, name: 1, profile: 1 }
)
Here, the profile is embedded directly inside the student document, so a separate query is not needed to retrieve it.
If the profile needs independent access control or management, storing it in a separate collection may be more appropriate.
A one-to-many relationship means one record is associated with multiple related records. For example, a student can make multiple fee payments.
Create a student document:
db.relationship_students.insertOne({
student_id: 102,
name: "Priya"
})
Insert related payment documents:
db.relationship_payments.insertMany([
{
payment_id: 1,
student_id: 102,
amount: 2000,
payment_date: "2026-09-01"
},
{
payment_id: 2,
student_id: 102,
amount: 1500,
payment_date: "2026-10-01"
}
])
Find all payments for student 102:
db.relationship_payments.find({
student_id: 102
})
Both payment documents reference the same student through
student_id.
Because payment history can grow over time, a separate payments collection is often a suitable design.
A many-to-many relationship means multiple records in one collection can be related to multiple records in another collection.
For example:
Create course documents:
db.relationship_courses.insertMany([
{
course_id: 1,
course_name: "Java"
},
{
course_id: 2,
course_name: "Python"
},
{
course_id: 3,
course_name: "Web Development"
}
])
Create enrollment documents:
db.relationship_enrollments.insertMany([
{
student_id: 101,
course_id: 1
},
{
student_id: 101,
course_id: 2
},
{
student_id: 102,
course_id: 1
},
{
student_id: 102,
course_id: 3
}
])
Find all courses associated with student 101:
db.relationship_enrollments.aggregate([
{
$match: {
student_id: 101
}
},
{
$lookup: {
from: "relationship_courses",
localField: "course_id",
foreignField: "course_id",
as: "courseDetails"
}
},
{
$unwind: "$courseDetails"
},
{
$project: {
_id: 0,
student_id: 1,
course_name: "$courseDetails.course_name"
}
}
])
The enrollment collection connects students and courses. Each enrollment document represents one student-course relationship.
MongoDB commonly represents relationships using either embedded documents or references.
{
name: "Rahul",
address: {
city: "Aurangabad",
state: "Bihar"
}
}
// students collection
{
student_id: 101,
name: "Rahul"
}
// relationship_payments collection
{
student_id: 101,
amount: 2000
}
| Embedding | Referencing |
|---|---|
| Related data is stored inside a document. | Related data is stored separately. |
| Convenient for small related information. | Useful for large or independently managed information. |
| Often retrieves related data in one query. | May require additional queries or $lookup. |
| May duplicate shared data. | Can reduce duplication of shared data. |
The $lookup stage combines documents from
another collection when specified fields match.
db.relationship_students.aggregate([
{
$lookup: {
from: "relationship_payments",
localField: "student_id",
foreignField: "student_id",
as: "paymentHistory"
}
}
])
Each student document receives a
paymentHistory array containing matching
payment documents. Students without matching payments
remain in the result with an empty array.
For this example, ensure the student documents contain
student_id values that match the payment
documents. The example collections created earlier
include such references for student 102.
Indexes can improve queries that frequently search related documents by a reference field.
db.relationship_payments.createIndex({
student_id: 1
})
db.relationship_enrollments.createIndex({
student_id: 1
})
db.relationship_enrollments.createIndex({
course_id: 1
})
If each student should enroll in a particular course only once, a compound unique index can enforce that rule:
db.relationship_enrollments.createIndex(
{
student_id: 1,
course_id: 1
},
{
unique: true
}
)
Create a unique index only after checking that existing documents contain no duplicate student-course pairs.
MongoDB does not automatically maintain references like a relational database with enforced foreign keys. Your application must decide how to handle related data when a record is updated or deleted.
For example, find payments before removing a student:
db.relationship_payments.find({
student_id: 102
})
Before deleting a student, decide whether their payment history must be retained for accounting or audit purposes. Do not automatically delete related records unless that behavior matches your application requirements.
For operations that must update multiple documents consistently, consider whether a MongoDB transaction is appropriate.
Complete the following tasks using MongoDB:
$lookup to display students with payment histories.$lookup to display enrollment details with course names.Note: Run each sample insertion only once. Re-running an insertion may create duplicate documents unless you use appropriate unique constraints.
1. Which relationship describes one student having multiple fee payments?
2. Which aggregation stage can combine matching documents from another collection?
3. What should you consider when choosing embedding or referencing?