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.
Our project will include the following features:
Database: studentManagementDB
Collections:
studentscoursespaymentsOpen 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.
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.
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.
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)
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.
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.
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.
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:
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.
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.
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.
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.
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([])}1. Which collection stores course information?
2. Which aggregation operator calculates the total of payment amounts?
3. Which index option prevents duplicate student IDs?