Lesson 42 of 50 – Library Management Database Project
84%

Library Management Database Using MongoDB

In this project, we will build a library management database using MongoDB. The database will store book details, library members, book issue records, and book return information. We will practise CRUD operations, queries, indexes, and aggregation.

1. Project Overview

Our library management system will manage:

  • Book details and availability
  • Library member information
  • Book issue records
  • Book return dates
  • Book categories and authors
  • Issue and return reports

Database name: libraryDB

Collections:

  • books
  • members
  • transactions

We will keep books, members, and transactions in separate collections so that each type of information can be managed independently.

2. Create the Database and Collections

Open MongoDB Shell:

mongosh

Select the database:

use libraryDB

Create the collections:

db.createCollection("books")
db.createCollection("members")
db.createCollection("transactions")

MongoDB creates a database when data is first stored in it. The collections can also be created automatically when documents are first inserted.

If a collection already exists, MongoDB will report an error for another createCollection() call. You can continue using the existing collection.

3. Design the Book Document

Example book document:

{
    book_id: 101,
    title: "Introduction to JavaScript",
    author: "John Smith",
    category: "Programming",
    publisher: "Tech Publications",
    price: 450,
    total_copies: 5,
    available_copies: 5,
    published_year: 2025
}

The book_id is an application-level identifier. MongoDB automatically adds an _id field when one is not supplied.

The total_copies field stores the total number of copies, while available_copies stores how many copies are currently available.

4. Insert Books

Insert one book using insertOne():

db.books.insertOne({
    book_id: 101,
    title: "Introduction to JavaScript",
    author: "John Smith",
    category: "Programming",
    publisher: "Tech Publications",
    price: 450,
    total_copies: 5,
    available_copies: 5,
    published_year: 2025
})

Insert several additional books:

db.books.insertMany([
    {
        book_id: 102,
        title: "Learning Python",
        author: "David Miller",
        category: "Programming",
        price: 550,
        total_copies: 4,
        available_copies: 4,
        published_year: 2024
    },
    {
        book_id: 103,
        title: "Computer Fundamentals",
        author: "Anita Sharma",
        category: "Computer Basics",
        price: 300,
        total_copies: 6,
        available_copies: 6,
        published_year: 2023
    },
    {
        book_id: 104,
        title: "Database Management",
        author: "Robert Brown",
        category: "Database",
        price: 600,
        total_copies: 3,
        available_copies: 3,
        published_year: 2025
    }
])

Run these insertions once in your practice database. Repeating them unchanged will create additional records unless a unique index prevents duplicate IDs.

5. Display and Search Books

Display all books:

db.books.find()

Display books in a readable format:

db.books.find().pretty()

Find a book by its ID:

db.books.findOne({
    book_id: 101
})

Find books in the Programming category:

db.books.find({
    category: "Programming"
})

Find books costing less than ₹500:

db.books.find({
    price: { $lt: 500 }
})

Find books with available copies:

db.books.find({
    available_copies: { $gt: 0 }
})

These queries can help staff find books by ID, category, price, or availability.

6. Create Library Members

Example member document:

{
    member_id: 201,
    name: "Rahul Kumar",
    mobile: "9876543210",
    email: "rahul@example.com",
    membership_type: "Student",
    city: "Aurangabad",
    active: true
}

Insert members:

db.members.insertMany([
    {
        member_id: 201,
        name: "Rahul Kumar",
        mobile: "9876543210",
        email: "rahul@example.com",
        membership_type: "Student",
        city: "Aurangabad",
        active: true
    },
    {
        member_id: 202,
        name: "Priya Singh",
        mobile: "9876543211",
        email: "priya@example.com",
        membership_type: "Student",
        city: "Patna",
        active: true
    },
    {
        member_id: 203,
        name: "Amit Kumar",
        mobile: "9876543212",
        email: "amit@example.com",
        membership_type: "General",
        city: "Gaya",
        active: true
    }
])

A member ID identifies the member within this application. In a real system, protect personal information and validate mobile numbers and email addresses before storing them.

7. Create Book Issue Transactions

A transaction document records which member borrowed which book and when the book is due.

db.transactions.insertOne({
    transaction_id: 301,
    book_id: 101,
    member_id: 201,
    issue_date: ISODate("2026-10-01T00:00:00Z"),
    due_date: ISODate("2026-10-15T00:00:00Z"),
    return_date: null,
    status: "ISSUED"
})

This design stores the application-level book and member IDs in the transaction. MongoDB does not automatically enforce foreign-key constraints between these collections.

Your application should verify that the book and member exist before creating the transaction.

The dates above are sample values for learning. Use appropriate dates for your own project.

8. Find Issued and Overdue Books

Find all books currently issued:

db.transactions.find({
    status: "ISSUED"
})

Find transactions that are overdue and not returned:

db.transactions.find({
    status: "ISSUED",
    due_date: { $lt: new Date() }
})

The second query compares the due date with the current date and time. A transaction is selected if it is still marked as issued and its due date has passed.

9. Issue a Book

Before issuing a book, check that a copy is available. In this beginner example, we will update the available copy count and create an issue transaction.

First, reduce the available copy count:

const bookResult = db.books.updateOne(
    {
        book_id: 101,
        available_copies: { $gt: 0 }
    },
    {
        $inc: {
            available_copies: -1
        }
    }
)

bookResult

If modifiedCount is 1, a copy was available and the count was reduced. If no document was modified, the book may not exist or no copies may be available.

Only after confirming the successful update should the application create the transaction record. In a real multi-step issue workflow, use a transaction where supported, or design retry and recovery logic so the book count and issue record cannot become inconsistent.

Example issue record:

db.transactions.insertOne({
    transaction_id: 302,
    book_id: 101,
    member_id: 202,
    issue_date: new Date(),
    due_date: new Date(
        Date.now() + 14 * 24 * 60 * 60 * 1000
    ),
    return_date: null,
    status: "ISSUED"
})

This two-command demonstration is not atomic. If one command succeeds and the other fails, the data may become inconsistent. Use a properly implemented transaction or another reliable application workflow for production systems. Do not repeat this example without checking the current availability count.

10. Return a Book

When a member returns a book, mark the transaction as returned and record the return date.

db.transactions.updateOne(
    {
        transaction_id: 301,
        status: "ISSUED"
    },
    {
        $set: {
            status: "RETURNED",
            return_date: new Date()
        }
    }
)

Increase the available copy count after confirming that the transaction was successfully changed from issued to returned.

db.books.updateOne(
    {
        book_id: 101
    },
    {
        $inc: {
            available_copies: 1
        }
    }
)

The copy count should only be increased once for a successful return. For a real application, perform the transaction status update and inventory change together in a database transaction where supported, or implement reliable safeguards against duplicate returns.

11. Join Books and Transactions Using $lookup

MongoDB's $lookup aggregation stage can combine matching documents from different collections.

db.transactions.aggregate([
    {
        $lookup: {
            from: "books",
            localField: "book_id",
            foreignField: "book_id",
            as: "book_details"
        }
    },
    {
        $unwind: "$book_details"
    },
    {
        $project: {
            _id: 0,
            transaction_id: 1,
            member_id: 1,
            status: 1,
            book_title: "$book_details.title",
            issue_date: 1,
            due_date: 1
        }
    }
])

The query matches each transaction's book_id with the corresponding book_id in the books collection. It then displays the book title alongside transaction details.

12. Library Reports Using Aggregation

Count the number of books in each category:

db.books.aggregate([
    {
        $group: {
            _id: "$category",
            totalBooks: { $sum: 1 },
            totalCopies: { $sum: "$total_copies" }
        }
    },
    {
        $sort: {
            totalBooks: -1
        }
    }
])

Count transactions by status:

db.transactions.aggregate([
    {
        $group: {
            _id: "$status",
            totalTransactions: { $sum: 1 }
        }
    }
])

These reports can help librarians understand book categories, total copies, and how many transactions are issued or returned.

13. Create Unique Indexes

Unique indexes help prevent duplicate application-level identifiers.

db.books.createIndex(
    { book_id: 1 },
    { unique: true }
)

db.members.createIndex(
    { member_id: 1 },
    { unique: true }
)

db.transactions.createIndex(
    { transaction_id: 1 },
    { unique: true }
)

If duplicate IDs already exist, index creation may fail. Check existing records before adding these indexes.

For frequently used queries, additional indexes may improve performance. Choose them based on actual query patterns and monitor their storage and write costs.

14. Practical Assignment

  1. Create the libraryDB database.
  2. Create the books, members, and transactions collections.
  3. Insert at least five books with different categories.
  4. Insert at least three library members.
  5. Search for books by title, author, and category.
  6. Find books whose available copy count is greater than zero.
  7. Create a transaction for an issued book.
  8. Find overdue books that have not been returned.
  9. Use $lookup to display book titles with transactions.
  10. Generate a report showing total books by category.
  11. Create unique indexes on application-level IDs.
  12. Explain how your application should prevent double issues and duplicate returns.

🧠 Quick Quiz

1. Which collection stores book details?




2. Which aggregation stage combines matching documents from another collection?




3. What helps prevent duplicate book IDs?