Todo (MongoDB)

This page documents the Todo schema for projects using MongoDB with Mongoose.

The Todo schema provides a production-ready model for managing tasks, complete with user validation and performance considerations.

This schema is designed to work with the User model from the Auth Domain. Ensure you have installed the authentication schemas before using Todos.

Installation Guide

To add this schema to your project, run:

npx servercn-cli add schema todo

During initialization, ensure you select MongoDB when prompted for the database.

Database Design

To see the complete database design, including the User schema from the Auth Domain, please click here visualization.

Database Design

Todo Model

The Todo Model stores individual task information and maintains a reference to the user who created it.

MVC Path: src/models/todo.model.ts
Feature Path: src/modules/todo/todo.model.ts

import mongoose, { Document, Model, Schema, Types } from "mongoose";
 
/**
 * Todo Interface
 * Defines the structure of a Todo document
 */
export interface ITodo extends Document {
  _id: Types.ObjectId;
  userId: Types.ObjectId;
 
  title: string;
  description?: string;
  completed: boolean;
 
  createdAt: Date;
  updatedAt: Date;
}
 
/**
 * Todo Schema definition
 */
const todoSchema = new Schema<ITodo>(
  {
    userId: {
      type: Schema.Types.ObjectId,
      ref: "User", // Reference to the User model
      required: [true, "User ID is required"],
      index: true // Indexed for faster user-specific queries
    },
    title: {
      type: String,
      required: [true, "Title is required"],
      trim: true,
      maxlength: [255, "Title cannot be longer than 255 characters"]
    },
    description: {
      type: String,
      trim: true,
      maxlength: [2000, "Description cannot be longer than 2000 characters"]
    },
    completed: {
      type: Boolean,
      default: false
    }
  },
  {
    timestamps: true // Automatically adds createdAt and updatedAt
  }
);
 
// Performance Indexes
todoSchema.index({ userId: 1, completed: 1 }); // Great for fetching pending/completed tasks for a user
todoSchema.index({ createdAt: -1 }); // Useful for sorting tasks by date
 
const Todo: Model<ITodo> =
  mongoose.models.Todo || mongoose.model<ITodo>("Todo", todoSchema);
 
export default Todo;

Installation:

npx servercn-cli add schema todo/todo

User Model

MVC Path: src/models/user.model.ts
Feature Path: src/modules/auth/user.model.ts

import mongoose, { Document, Model, Schema } from "mongoose";
 
export interface IAvatar {
  public_id: string;
  url: string;
  size: number;
}
 
export interface IUser extends Document {
  _id: mongoose.Types.ObjectId;
  name: string;
  email: string;
  password?: string;
  role: "user" | "admin";
  isEmailVerified: boolean;
  lastLoginAt?: Date;
  failedLoginAttempts: number;
  lockUntil?: Date;
  avatar?: IAvatar;
 
  provider: "local" | "google" | "github";
  providerId?: string;
 
  isDeleted: boolean;
  deletedAt?: Date | null;
  reActivateAvailableAt?: Date | null;
 
  createdAt: Date;
  updatedAt: Date;
}
 
const userSchema = new Schema<IUser>(
  {
    name: {
      type: String,
      required: [true, "Name is required"],
      trim: true
    },
    email: {
      type: String,
      required: [true, "Email is required"],
      unique: true,
      lowercase: true,
      trim: true
    },
    password: {
      type: String,
      select: false,
      default: null
    },
    provider: {
      type: String,
      enum: ["local", "google", "github"],
      default: "local"
    },
    providerId: {
      type: String,
      default: null
    },
    role: {
      type: String,
      enum: ["user", "admin"],
      default: "user"
    },
    avatar: {
      public_id: String,
      url: String,
      size: Number
    },
    isEmailVerified: {
      type: Boolean,
      default: false
    },
    lastLoginAt: {
      type: Date
    },
    failedLoginAttempts: {
      type: Number,
      required: true,
      default: 0
    },
    lockUntil: {
      type: Date
    },
    isDeleted: {
      type: Boolean,
      default: false
    },
    deletedAt: {
      type: Date,
      default: null
    },
    reActivateAvailableAt: {
      type: Date,
      default: null
    }
  },
  {
    timestamps: true
  }
);
 
// Performance Indexes
userSchema.index({ provider: 1, providerId: 1 }); // Quick lookup for OAuth
userSchema.index({ role: 1 });
userSchema.index({ isDeleted: 1 }); // Optimized for soft-delete queries
 
const User: Model<IUser> =
  mongoose.models.User || mongoose.model<IUser>("User", userSchema);
 
export default User;

Relationship Reference

The userId field uses a reference to the User model. When querying todos, you can easily populate user information:

const userTodos = await Todo.find({ userId: req.user._id })
  .populate("userId", "name email")
  .sort("-createdAt");

Key Benefits

  • Strict Validation: Ensures all todos have a user and a title.
  • Auto-Timestamps: Leverages Mongoose's built-in timestamp support.
  • Optimized Queries: Includes indexes for common access patterns.
  • MLean Ready: Compatible with .lean() for faster read operations.

File & Folder Structure

ServerCN

Select a file to view its contents

Installation

npx servercn-cli add schema todo