Lesson 49 of 50 – MongoDB Mini Project
98%

MongoDB Mini Project: Student Management System

In this mini project, you will build a Student Management System database using MongoDB. You will store student information, course details, and fee payments. You will also practise CRUD operations, indexes, and aggregation reports.

1. Project Requirements

Our project will include the following features:

  • Manage student records.
  • Store course names, fees, and duration.
  • Record student fee payments.
  • Search students by ID, name, and course.
  • Update student details.
  • Calculate pending fees.
  • Generate course-wise student reports.
  • Generate monthly payment reports.
  • Create indexes to support common queries.

Database: studentManagementDB

Collections:

  • students
  • courses
  • payments

2. Create the Database and Collections

Open MongoDB Shell:

mongosh

Select the database:

use studentManagementDB

Create the collections:

db.createCollection("students")
db.createCollection("courses")
db.createCollection("payments")

MongoDB creates a database when data is stored or a collection is created. If the collections already exist, continue using them.

3. Insert Course Records

Insert the available courses:

db.courses.insertMany([
    {
        course_id: 1,
        course_name: "ADCA",
        duration_months: 12,
        total_fee: 10500
    },
    {
        course_id: 2,
        course_name: "Python Programming",
        duration_months: 6,
        total_fee: 12000
    },
    {
        course_id: 3,
        course_name: "Web Development",
        duration_months: 6,
        total_fee: 15000
    },
    {
        course_id: 4,
        course_name: "Tally Prime",
        duration_months: 3,
        total_fee: 4000
    }
])

Display all courses:

db.courses.find()

Find a specific course:

db.courses.findOne({
    course_id: 1
})

Course fees are stored as numeric values. In a real application, define a consistent currency and fee policy before accepting payments.

Run sample insertions only once to avoid duplicate records.

4. Insert Student Records

Insert sample students:

db.students.insertMany([
    {
        student_id: 1001,
        name: "Rahul Kumar",
        mobile: "9876543210",
        city: "Patna",
        course_id: 1,
        admission_date: ISODate("2026-01-10T00:00:00Z"),
        status: "Active"
    },
    {
        student_id: 1002,
        name: "Priya Sharma",
        mobile: "9876543211",
        city: "Gaya",
        course_id: 2,
        admission_date: ISODate("2026-02-15T00:00:00Z"),
        status: "Active"
    },
    {
        student_id: 1003,
        name: "Amit Singh",
        mobile: "9876543212",
        city: "Patna",
        course_id: 3,
        admission_date: ISODate("2026-03-01T00:00:00Z"),
        status: "Active"
    },
    {
        student_id: 1004,
        name: "Neha Verma",
        mobile: "9876543213",
        city: "Delhi",
        course_id: 4,
        admission_date: ISODate("2026-03-20T00:00:00Z"),
        status: "Active"
    },
    {
        student_id: 1005,
        name: "Ravi Kumar",
        mobile: "9876543214",
        city: "Gaya",
        course_id: 1,
        admission_date: ISODate("2026-04-05T00:00:00Z"),
        status: "Active"
    }
])

Display all students:

db.students.find()

Find a student by ID:

db.students.findOne({
    student_id: 1001
})

The course_id field references a course record. MongoDB does not automatically enforce foreign keys, so the application must ensure that referenced courses exist.

5. Search and Filter Students

Find students from Patna:

db.students.find({
    city: "Patna"
})

Find active students:

db.students.find({
    status: "Active"
})

Find students enrolled in course ID 1:

db.students.find({
    course_id: 1
})

Display only names and mobile numbers:

db.students.find(
    {},
    {
        _id: 0,
        name: 1,
        mobile: 1
    }
)

Sort students by name:

db.students.find().sort({
    name: 1
})

Display the first three students:

db.students.find()
    .limit(3)

6. Update Student Details

Update a student's city:

db.students.updateOne(
    {
        student_id: 1001
    },
    {
        $set: {
            city: "Gaya"
        }
    }
)

Change a student's status:

db.students.updateOne(
    {
        student_id: 1004
    },
    {
        $set: {
            status: "Inactive"
        }
    }
)

Verify the update:

db.students.findOne({
    student_id: 1004
})

The $set operator updates selected fields without replacing the whole document.

7. Record Fee Payments

Insert sample fee payments:

db.payments.insertMany([
    {
        payment_id: 5001,
        student_id: 1001,
        amount: 5000,
        payment_date: ISODate("2026-01-15T00:00:00Z"),
        payment_mode: "Cash",
        status: "Completed"
    },
    {
        payment_id: 5002,
        student_id: 1001,
        amount: 2500,
        payment_date: ISODate("2026-02-15T00:00:00Z"),
        payment_mode: "UPI",
        status: "Completed"
    },
    {
        payment_id: 5003,
        student_id: 1002,
        amount: 6000,
        payment_date: ISODate("2026-02-20T00:00:00Z"),
        payment_mode: "UPI",
        status: "Completed"
    },
    {
        payment_id: 5004,
        student_id: 1003,
        amount: 7500,
        payment_date: ISODate("2026-03-10T00:00:00Z"),
        payment_mode: "Bank Transfer",
        status: "Completed"
    },
    {
        payment_id: 5005,
        student_id: 1005,
        amount: 3000,
        payment_date: ISODate("2026-04-10T00:00:00Z"),
        payment_mode: "Cash",
        status: "Completed"
    }
])

Display all payments:

db.payments.find()

Find payments for student 1001:

db.payments.find({
    student_id: 1001,
    status: "Completed"
})

In this project, only payments marked Completed count toward fees paid. A production payment system should validate transactions and prevent duplicate payment records.

8. Calculate Total Fees Paid by Each Student

Use aggregation to calculate completed payments:

db.payments.aggregate([
    {
        $match: {
            status: "Completed"
        }
    },
    {
        $group: {
            _id: "$student_id",
            totalPaid: {
                $sum: "$amount"
            },
            paymentCount: {
                $sum: 1
            }
        }
    },
    {
        $sort: {
            totalPaid: -1
        }
    }
])

The result contains one document for each student who has at least one completed payment.

The aggregation uses $group to group payments by student ID and $sum to calculate total payments.

9. Calculate Pending Fees

First, combine students with their course records and completed payments. Then calculate the pending amount.

db.students.aggregate([
    {
        $lookup: {
            from: "courses",
            localField: "course_id",
            foreignField: "course_id",
            as: "course_details"
        }
    },
    {
        $unwind: "$course_details"
    },
    {
        $lookup: {
            from: "payments",
            let: {
                sid: "$student_id"
            },
            pipeline: [
                {
                    $match: {
                        $expr: {
                            $eq: [
                                "$student_id",
                                "$$sid"
                            ]
                        },
                        status: "Completed"
                    }
                },
                {
                    $group: {
                        _id: null,
                        totalPaid: {
                            $sum: "$amount"
                        }
                    }
                }
            ],
            as: "payment_summary"
        }
    },
    {
        $set: {
            totalPaid: {
                $ifNull: [
                    {
                        $arrayElemAt: [
                            "$payment_summary.totalPaid",
                            0
                        ]
                    },
                    0
                ]
            }
        }
    },
    {
        $project: {
            _id: 0,
            student_id: 1,
            name: 1,
            course: "$course_details.course_name",
            totalFee: "$course_details.total_fee",
            totalPaid: 1,
            pendingFee: {
                $max: [
                    0,
                    {
                        $subtract: [
                            "$course_details.total_fee",
                            "$totalPaid"
                        ]
                    }
                ]
            }
        }
    },
    {
        $sort: {
            student_id: 1
        }
    }
])

This report displays:

  • Student ID and name
  • Course name
  • Total course fee
  • Total completed payments
  • Pending fee, never below zero in this report

This example assumes each student has one course and the course fee is the full amount due. Discounts, refunds, scholarships, and fee revisions would require additional business rules.

10. Generate Course-Wise Student Reports

Count students enrolled in each course:

db.students.aggregate([
    {
        $group: {
            _id: "$course_id",
            totalStudents: {
                $sum: 1
            }
        }
    },
    {
        $lookup: {
            from: "courses",
            localField: "_id",
            foreignField: "course_id",
            as: "course_details"
        }
    },
    {
        $unwind: "$course_details"
    },
    {
        $project: {
            _id: 0,
            courseName: "$course_details.course_name",
            totalStudents: 1
        }
    },
    {
        $sort: {
            totalStudents: -1
        }
    }
])

This report helps identify how many students are enrolled in each course.

11. Generate Monthly Payment Reports

Calculate completed payment totals by month:

db.payments.aggregate([
    {
        $match: {
            status: "Completed"
        }
    },
    {
        $group: {
            _id: {
                $dateToString: {
                    format: "%Y-%m",
                    date: "$payment_date",
                    timezone: "UTC"
                }
            },
            totalCollection: {
                $sum: "$amount"
            },
            totalPayments: {
                $sum: 1
            }
        }
    },
    {
        $sort: {
            _id: 1
        }
    }
])

The $dateToString expression groups payment dates into year-month values such as 2026-01.

The timezone is set to UTC for this example. Choose the business's timezone when generating real reports.

12. Create Unique Indexes

Create unique indexes for application-level IDs:

db.students.createIndex(
    { student_id: 1 },
    { unique: true }
)

db.courses.createIndex(
    { course_id: 1 },
    { unique: true }
)

db.payments.createIndex(
    { payment_id: 1 },
    { unique: true }
)

Create indexes for common searches:

db.students.createIndex({
    name: 1
})

db.students.createIndex({
    course_id: 1
})

db.payments.createIndex({
    student_id: 1,
    payment_date: -1
})

View indexes:

db.students.getIndexes()
db.courses.getIndexes()
db.payments.getIndexes()

Check for duplicate application IDs before creating unique indexes. The compound payment index can help queries that filter by student ID and sort by payment date.

13. Project Completion Checklist

Complete each task as you build the project:

{@body const tasks = [ "Create the studentManagementDB database.", "Create students, courses, and payments collections.", "Insert course and student records.", "Search students by ID, city, and course.", "Update student information.", "Record and search fee payments.", "Calculate total fees paid by each student.", "Generate pending-fee reports.", "Generate course-wise student reports.", "Generate monthly payment reports.", "Create unique indexes and useful search indexes.", "Test aggregation queries and verify the results." ]} {@body const [completedTasks, setCompletedTasks] = DIL.useState([])} {completedTasks.length} of {tasks.length} tasks completed {#each tasks as task, i} setCompletedTasks(old => checked ? [...old, i] : old.filter(n => n !== i))}> {task} {/each}

🧠 Quick Quiz

1. Which collection stores course information?




2. Which aggregation operator calculates the total of payment amounts?




3. Which index option prevents duplicate student IDs?