Lesson 28 of 50 – Relationships in MongoDB
56%

Relationships in MongoDB

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.

1. What Is a Relationship?

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:

  • Student and student profile.
  • Student and fee payments.
  • Customer and orders.
  • Department and employees.
  • Students and courses.

MongoDB does not automatically enforce relational foreign-key constraints. Applications must manage references and related data appropriately.

2. Types of Relationships

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

3. One-to-One Relationship

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.

4. One-to-Many Relationship

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.

5. Many-to-Many Relationship

A many-to-many relationship means multiple records in one collection can be related to multiple records in another collection.

For example:

  • A student can enroll in several courses.
  • A course can contain several students.

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.

6. Embedding vs Referencing

MongoDB commonly represents relationships using either embedded documents or references.

Embedding Example
{
    name: "Rahul",
    address: {
        city: "Aurangabad",
        state: "Bihar"
    }
}
Referencing Example
// 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.

7. Use $lookup to Join Collections

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.

8. Indexes for Relationships

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.

9. Maintain Relationship Data

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.

10. Practical Assignment

Complete the following tasks using MongoDB:

  1. Create a student document with an embedded address.
  2. Create a separate collection for student fee payments.
  3. Insert three payments associated with one student.
  4. Create course and enrollment collections.
  5. Represent a many-to-many relationship between students and courses.
  6. Use $lookup to display students with payment histories.
  7. Use $lookup to display enrollment details with course names.
  8. Create indexes on frequently queried reference fields.
  9. Explain when embedding is preferable to referencing.
  10. Describe how your application should handle deletion of related records.

Note: Run each sample insertion only once. Re-running an insertion may create duplicate documents unless you use appropriate unique constraints.

🧠 Quick Quiz

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?