Mastering MongoDB Data Modeling

Mastering MongoDB Data Modeling

A Comprehensive Guide

ยท

6 min read

MongoDB is a cool tool for developers, giving lots of flexibility in how we organize data. Let's explore it together with examples from a Todo app, a Hospital Management System, and an e-commerce app. Wanna try it out? You can play around with the code here.

1. MongoDB Data Modeling Basics

Before we dive into specific examples, let's understand the fundamentals of MongoDB data modeling.

1.1 Models and Schemas

In MongoDB, a model represents a structured blueprint for storing data. Each model is associated with a schema, defining the properties, types, and relationships between data points.

1.2 Mongoose Integration

Mongoose, an elegant MongoDB object modeling tool, simplifies the interaction with MongoDB. It provides an expressive syntax for defining schemas and models.

2. Todo App: Simple Yet Effective

Let's start with a Todo app, a classic example that introduces the basic concepts of MongoDB data modeling.

2.1 Todo Model

// todo.model.js
import mongoose from "mongoose";

const todoSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
  },
  content: {
    type: String,
    required: false,
  },
  completed: {
    type: Boolean,
    default: false,
  },
}, {
  timestamps: true
});

export const Todo = mongoose.model("Todo", todoSchema);

2.1.1 Explanation

  • title: Title of the todo, required.
  • content: Optional content of the todo.
  • completed: Completion status, default is false.

2.2 SubTodo Model

// subtodo.model.js
import mongoose from "mongoose";

const subTodoSchema = new mongoose.Schema({
  title: {
    type: String,
    required: true,
  },
  content: {
    type: String,
    required: false,
  },
  completed: {
    type: Boolean,
    default: false,
  },
  todo: {
    type: mongoose.Schema.Types.ObjectId,
    ref: 'Todo',
    required: true,
  },
}, {
  timestamps: true
});

export const SubTodo = mongoose.model("SubTodo", subTodoSchema);

2.2.1 Explanation

  • title: Title of the subtodo, required.
  • content: Optional content of the subtodo.
  • completed: Completion status, default is false.
  • todo: Reference to the parent todo.

3. Hospital Management System: A Structured Approach

Moving on to a more complex example, let's explore the data modeling for a Hospital Management System.

3.1 Doctor Model

// doctor.model.js
import mongoose from "mongoose";

const DoctorSchema = new mongoose.Schema(
  {
    name: { type: String, required: true },
    qualification: { type: String, required: true },
    experienceInYears: { type: Number, default: 0 },
    worksInHospitals: [
      { type: mongoose.Schema.Types.ObjectId, ref: "Hospital" },
    ],
    salary: { type: Number, required: true },
  },
  { timestamps: true },
);

export const Doctor = mongoose.model("Doctor", DoctorSchema);

3.1.1 Explanation

  • name: Doctor's full name, required.
  • qualification: Doctor's qualification, required.
  • experienceInYears: Doctor's experience, default is 0.
  • worksInHospitals: Array of hospital references.
  • salary: Doctor's salary, required.

3.2 Patient Model

// patient.model.js
import mongoose from "mongoose";

const PatientSchema = new mongoose.Schema(
  {
    name: { type: String, required: true },
    diagnoseWith: { type: String, required: true },
    address: { type: String, required: true },
    age: { type: Number, required: true },
    bloodGroup: { type: String, required: true },
    gender: {
      type: String,
      enum: ["Male", "Female", "Others"],
      required: true,
    },
    admittedIn: { type: mongoose.Schema.Types.ObjectId, ref: "Hospital" },
  },
  { timestamps: true },
);

export const Patient = mongoose.model("Patient", PatientSchema);

3.2.1 Explanation

  • name: Patient's name, required.
  • diagnoseWith: Patient's diagnosis, required.
  • address: Patient's address, required.
  • age: Patient's age, required.
  • bloodGroup: Patient's blood group, required.
  • gender: Patient's gender, with enum values.
  • admittedIn: Reference to the admitting hospital.

3.3 Hospital Model

// hospital.model.js
import mongoose from "mongoose";

const HospitalSchema = new mongoose.Schema(
  {
    name: { type: String, required: true },
    addressLine1: { type: String, required: true },
    addressLine2: { type: String },
    city: { type: String, required: true },
    pincode: { type: String, required: true },
    specializedIn: [
      { type: String },
    ],
  },
  { timestamps: true },
);

export const Hospital = mongoose.model("Hospital", HospitalSchema);

3.3.1 Explanation

  • name: Hospital's name, required.
  • addressLine1: First line of the hospital's address, required.
  • addressLine2: Second line of the hospital's address.
  • city: Hospital's city, required.
  • pincode: Hospital's pin code, required.
  • specializedIn: Array of specialization areas.

4. eCommerce Application: Bridging Complexity and Simplicity

Let's now explore the data modeling for an eCommerce application, a scenario that involves intricate relationships and nested structures.

4.1 User Model

// user.model.js
import mongoose from "mongoose";

const userSchema = new mongoose.Schema(
  {
    username: {
      type: String,
      required: true,
      unique: true,
      lowercase: true,
    },
    email: {
      type: String,
      required: true,
      unique: true,
      lowercase: true,
    },
    password: {
      type: String,
      required: true,
    },
  },
  { timestamps: true }
);

export const User = mongoose.model("User", userSchema);

4.1.1 Explanation

  • username: Unique username in lowercase.
  • email: Unique email address in lowercase.
  • password: User password.

4.2 Category Model

// category.model.js
import mongoose from "mongoose";

const categorySchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: true,
    },
  },
  { timestamps: true }
);

export const Category = mongoose.model("Category", categorySchema);

4.2.1 Explanation

  • name: Name of

    the category.

4.3 Product Model

// product.model.js
import mongoose from "mongoose";

const productSchema = new mongoose.Schema(
  {
    description: {
      type: String,
      required: true,
    },
    name: {
      type: String,
      required: true,
    },
    productImage: {
      type: String,
    },
    price: {
      type: Number,
      default: 0,
      required: true,
    },
    stock: {
      type: Number,
      default: 0,
    },
    category: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "Category",
      required: true,
    },
    owner: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
      required: true,
    },
  },
  { timestamps: true }
);

export const Product = mongoose.model("Product", productSchema);

4.3.1 Explanation

  • description: Description of the product.
  • name: Name of the product.
  • productImage: URL for the product image.
  • price: Price of the product.
  • stock: Quantity in stock.
  • category: Reference to the Category model.
  • owner: Reference to the User model representing the product owner.

4.4 Order Model

// order.model.js
import mongoose from "mongoose";

const orderItemsSchema = new mongoose.Schema({
  productId: {
    type: mongoose.Schema.Types.ObjectId,
    ref: "Product",
  },
  quantity: {
    type: Number,
    required: true,
  },
});

const orderSchema = new mongoose.Schema(
  {
    orderPrice: {
      type: Number,
      required: true,
    },
    customer: {
      type: mongoose.Schema.Types.ObjectId,
      ref: "User",
    },
    orderItems: {
      type: [orderItemsSchema],
      required: true,
    },
    address: {
      type: String,
      required: true,
    },
    status: {
      type: String,
      enum: ["pending", "processing", "delivered", "cancelled"],
      default: "pending",
    },
  },
  { timestamps: true }
);

export const Order = mongoose.model("Order", orderSchema);

4.4.1 Explanation

  • orderPrice: Total price of the order.
  • customer: Reference to the User model representing the customer.
  • orderItems: Array of nested orderItemsSchema, each representing an order item.
  • address: Shipping address for the order.
  • status: Order status, with possible values "pending," "processing," "delivered," or "cancelled."

5. Conclusion

Understanding MongoDB data modeling is crucial for developers. Our examples highlight MongoDB's versatility and how Mongoose streamlines the process. Remember to customize these models for your projects.

For more complex examples, explore the YT-Backend repo. Don't forget to star it! ๐Ÿ˜œ

Happy coding! ๐Ÿš€

ย