DEV Community

Cover image for MongoDB with Mongoose: Schema Design, CRUD Operations & Validations (Part 2)
Ahmed Afzal
Ahmed Afzal

Posted on

MongoDB with Mongoose: Schema Design, CRUD Operations & Validations (Part 2)

Before diving in, make sure you’ve read Part 1 of this series, where we explore what MongoDB is, its document-based structure, and why it's different from relational databases.


Introduction

In Part 1, we explored the foundations of MongoDB — a NoSQL, document-oriented database. Now in Part 2, we’ll take the next step by learning how to interact with MongoDB using Mongoose, a powerful ODM (Object Data Modeling) library for Node.js. We'll cover:

  • Schema design in MongoDB
  • Data types and relationships
  • Setting up Mongoose
  • CRUD operations
  • Validations in Mongoose
  • Key methods like .save(), .find(), .findById(), etc.

Let’s dive in! 🚀


1. Understanding Schema-less Nature of MongoDB

🔹 What is a Schema?

In relational databases like MySQL or PostgreSQL, a schema defines the structure of tables, columns, and their relationships. For example:

  • Student
  • Course
  • Section

Relational Database Schema Example

Each has a strict format and is connected through foreign keys. If you want to change the structure (add a new field), you need to alter the schema manually.

📌 This strict structure enforces consistency but reduces flexibility.

🔹 MongoDB is Schema-less

MongoDB doesn’t enforce any schema. Instead, it stores data in JSON-like documents, making it highly flexible and scalable.

For example, this is perfectly valid in MongoDB:

{ "name": "Ahmed Afzal", "age": 25 }

Enter fullscreen mode Exit fullscreen mode

You can add more fields later without modifying the existing schema. However, this doesn't mean we should store data in a disorganized way. Best practice: define a logical document structure for consistency.


2. Data Types in MongoDB

Like all databases, MongoDB supports different data types:

Type Example
String { "name": "Ahmed" }
Number { "age": 25 }, { "price": 99.99 }
Boolean { "isActive": true }
Date { "createdAt": ISODate("2025-07-07T00:00:00Z") }
Array { "skills": ["React", "Node.js"] }
Object { "address": { "city": "Karachi", "country": "Pakistan" } }
Null { "middleName": null }

3. Embedded vs Referenced Documents

MongoDB allows you to structure related data in two ways:

✅ Embedded Documents (Denormalized)

Nested documents inside a parent document.

{
  "title": "Intro to MongoDB",
  "comments": [
    { "user": "Ali", "message": "Great post!" },
    { "user": "Sara", "message": "Helpful!" }
  ]
}

Enter fullscreen mode Exit fullscreen mode

Benefits:

  • Fast reads
  • Fewer queries

Drawbacks:

  • Documents can become large (max 16MB)
  • Harder to update deeply nested data

🔗 Referenced Documents (Normalized)

Separate documents linked by IDs.

// Blog
{ "_id": 1, "title": "Intro to MongoDB", "comments": [101, 102] }

// Comments Collection
{ "_id": 101, "postId": 1, "message": "Nice Article" }
{ "_id": 102, "postId": 1, "message": "Great Concept" }

Enter fullscreen mode Exit fullscreen mode

Benefits:

  • More scalable
  • Reusable data

Drawbacks:

  • Slower reads due to multiple queries

4. Relationships in MongoDB

➤ One-to-One (1:1)

Each document relates to one other.

// User
{ "_id": 101, "name": "Ahmed" }

// Profile
{ "_id": 1, "userId": 101, "bio": "Engineer" }

Enter fullscreen mode Exit fullscreen mode

➤ One-to-Many (1:N)

One document relates to many others.

// Author
{ "_id": 1, "name": "Ahmed" }

// Books
[
  { "_id": 101, "authorId": 1, "title": "Book A" },
  { "_id": 102, "authorId": 1, "title": "Book B" }
]

Enter fullscreen mode Exit fullscreen mode

➤ Many-to-Many (M:N)

Both documents relate to many others.

// Student
{ "_id": 1, "name": "Ahmed", "enrolledCourses": [101, 102] }

// Courses
{ "_id": 101, "title": "React JS", "students": [1, 2] }

Enter fullscreen mode Exit fullscreen mode

5. What is Mongoose and Why Use It?

Mongoose is an ODM library for Node.js that helps:

  • Enforce structure (via schemas)
  • Apply validations
  • Easily perform CRUD operations

Without Mongoose, MongoDB allows unstructured data — e.g., inserting a string into a number field would still work. Mongoose prevents that.


6. Setting Up Mongoose in Node.js

✅ Prerequisites

  • Install Node.js
  • Ensure MongoDB is running locally (mongod)
  • Optionally use MongoDB Compass

📁 Folder Structure

mongoose-app/
├── models/
│   └── User.js
├── app.js

Enter fullscreen mode Exit fullscreen mode

📦 Initialize Project

mkdir mongoose-app
cd mongoose-app
npm init -y
npm install mongoose

Enter fullscreen mode Exit fullscreen mode

🔌 Connect to MongoDB

// app.js
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/mydb', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
})
.then(() => console.log("Connected to MongoDB"))
.catch((err) => console.error("Connection error:", err));

Enter fullscreen mode Exit fullscreen mode

7. Creating Schemas and Models

// models/User.js
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  name: String,
  age: Number,
});

const User = mongoose.model('User', userSchema);

module.exports = User;

Enter fullscreen mode Exit fullscreen mode

8. CRUD Operations in Mongoose

📌 Create

const ahmed = new User({ name: "Ahmed", age: 25 });
ahmed.save();

Enter fullscreen mode Exit fullscreen mode

📌 Read

User.find().then(users => console.log(users));

Enter fullscreen mode Exit fullscreen mode

📌 Update

User.updateOne({ name: "Ahmed" }, { age: 30 });

Enter fullscreen mode Exit fullscreen mode

📌 Delete

User.deleteOne({ name: "Ahmed" });

Enter fullscreen mode Exit fullscreen mode

✅ Full Example (app.js)

const mongoose = require('mongoose');
const User = require('./models/User');

mongoose.connect('mongodb://localhost:27017/mydb', {
  useNewUrlParser: true,
  useUnifiedTopology: true,
})
.then(async () => {
  console.log("Connected to MongoDB");

  // Create
  const user = new User({ name: "Ahmed", age: 22 });
  await user.save();

  // Read
  const users = await User.find();
  console.log(users);

  // Update
  await User.updateOne({ name: "Ahmed" }, { age: 30 });

  // Delete
  await User.deleteOne({ name: "Ahmed" });

  mongoose.disconnect();
})
.catch(console.error);

Enter fullscreen mode Exit fullscreen mode

9. Mongoose Validations

Without validation:

const user = new User({ name: 123, age: "abc" }); // Allowed!

Enter fullscreen mode Exit fullscreen mode

With validation:

const userSchema = new mongoose.Schema({
  name: { type: String, required: true, minlength: 3 },
  age: { type: Number, required: true, min: 18, max: 60 },
  email: { type: String, required: true, match: /.+\@.+\..+/ }
});

Enter fullscreen mode Exit fullscreen mode

✨ Example:

const user = new User({
  name: "Ah",    // too short
  age: 17,       // too young
  email: "invalidemail"
});

user.save().catch(err => console.log("Validation Error:", err.message));

Enter fullscreen mode Exit fullscreen mode

🔧 Other Validation Options

Validator Description
required Must be present
min / max Numbers only
minlength / maxlength String length
match Regex pattern
enum Limited values
status: {
  type: String,
  enum: ['active', 'inactive', 'pending'],
  default: 'pending'
}

Enter fullscreen mode Exit fullscreen mode

10. Mongoose Query Methods Explained

Method Use
.save() Save new document
.find() Get all or filtered documents
.findOne() Get one document
.findById() Get by ObjectId
.updateOne() Update first match
.findByIdAndUpdate() Update by ID and return updated doc
.deleteOne() Delete first match
.findByIdAndDelete() Delete by ID

Conclusion

In this part, you learned how to:

  • Understand MongoDB’s flexible data model
  • Use embedded and referenced documents
  • Create and validate schemas using Mongoose
  • Perform full CRUD operations

🔁 If you haven't already, read Part 1 here to better understand MongoDB fundamentals.


👉 Coming Up Next (Part 3 – Final Part):

In the next article, we’ll explore:

  • Relationships using populate()
  • Advanced queries and filtering
  • Indexing for performance
  • Aggregation framework
  • Project structure best practices

Stay tuned! 🎯

Top comments (0)