DEV Community

Prathviraj H
Prathviraj H

Posted on

**Mastering MongoDB with Mongoose: How CampusX Optimizes Data Queries**

MongoDB, a NoSQL database, is a powerhouse when handling large-scale data. CampusX leverages MongoDB along with Mongoose, an ODM (Object Data Modeling) library, to structure and optimize database interactions. One of the core aspects of our implementation is MongoDB's aggregation pipelines, which allow us to efficiently fetch, transform, and compute data in a single query.


What is Mongoose?

Mongoose is a schema-based solution for MongoDB that provides a layer of abstraction, making it easier to interact with the database. It enables defining schemas, applying validation, and using middleware for handling complex operations.

Why Use Aggregation Pipelines?

MongoDB’s aggregation framework is a powerful feature that allows performing complex data transformations on the server side. Instead of fetching raw data and processing it in the application, aggregation pipelines execute these operations directly in the database, improving efficiency and performance.


Example: Fetching a Post with Mongoose Aggregation

One of the key functionalities in CampusX is retrieving posts along with associated details such as the author, comments, and follower count. Instead of making multiple queries, we optimize this using a MongoDB aggregation pipeline:

const post = await Post.aggregate([
    { $match: { _id: new mongoose.Types.ObjectId(postId) } },
    {
      $lookup: {
        from: "users",
        localField: "author",
        foreignField: "_id",
        as: "authorDetails",
      },
    },
    { $unwind: "$authorDetails" },
    {
      $lookup: {
        from: "comments",
        localField: "_id",
        foreignField: "post",
        as: "comments",
      },
    },
    {
      $lookup: {
        from: "subscriptions",
        localField: "author",
        foreignField: "channel",
        as: "followers",
      },
    },
    {
      $addFields: {
        likeCount: { $size: "$likes" },
        commentCount: { $size: "$comments" },
        followerCount: { $size: "$followers" },
      },
    },
]);
Enter fullscreen mode Exit fullscreen mode

Breakdown of the Pipeline Stages:

  1. $match: Filters the post by its unique _id.
  2. $lookup (Users Collection): Joins the users collection to get the author details.
  3. $unwind: Converts the array of author details into a single object.
  4. $lookup (Comments Collection): Fetches all comments associated with the post.
  5. $lookup (Subscriptions Collection): Retrieves followers of the author.
  6. $addFields: Computes additional fields like likeCount, commentCount, and followerCount for quick reference.

This approach ensures we fetch all necessary data in one optimized query rather than executing multiple queries separately.


Schema Definition and Middleware in Mongoose

Our Post schema defines relationships and pre-processing steps before deletion.

const postSchema = new mongoose.Schema(
  {
    author: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
    content: { type: String, required: true },
    image: { type: String },
    category: {
      type: String,
      enum: ["general", "exams", "placements", "competitions", "hackathons", "lost_found"],
      default: "general",
    },
    likes: [{ type: mongoose.Schema.Types.ObjectId, ref: "User" }],
    likesCount: { type: Number, default: 0 },
    comments: [{ type: mongoose.Schema.Types.ObjectId, ref: "Comment" }],
  },
  { timestamps: true }
);
Enter fullscreen mode Exit fullscreen mode

Handling Deletions with Middleware

Mongoose allows us to trigger logic before deleting a post. The following middleware ensures associated comments and images are also removed when a post is deleted:

postSchema.pre("deleteOne", { document: true, query: false }, async function (next) {
    console.log(`Deleting comments and image for post: ${this._id}`);

    // Delete Comments
    await Comment.deleteMany({ post: this._id });

    // Delete Post Image if Exists
    await deleteImage(this.image);
    next();
});

postSchema.pre("deleteMany", { document: false, query: true }, async function (next) {
    const posts = await this.model.find(this.getFilter());

    for (const post of posts) {
        console.log(`Deleting comments and image for post: ${post._id}`);

        await Comment.deleteMany({ post: post._id });
        await deleteImage(post.image);
    }
    next();
});
Enter fullscreen mode Exit fullscreen mode

This ensures no orphaned records are left in the database after a post is deleted.


Why This Matters for CampusX?

  1. Performance Boost: The aggregation pipeline reduces multiple database calls, making queries significantly faster.
  2. Data Integrity: Middleware ensures that when a post is deleted, related comments and images are also removed.
  3. Schema Validation: Mongoose enforces structured data, reducing potential errors.
  4. Better Readability & Maintainability: Using Mongoose schemas and middleware makes the codebase easier to manage.

By combining MongoDB’s raw power with Mongoose’s flexibility, CampusX ensures an efficient, scalable, and maintainable database structure. 🚀

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay