Mongoose + Node.js: My Journey from Basics to Advanced

Photo by RetroSupply on Unsplash

Mongoose + Node.js: My Journey from Basics to Advanced

It’s been a while when I started backend development with Node.js, one of the challenges I faced was managing databases.

Coming from a relational database background, transitioning to a NoSQL database like MongoDB felt intimidating at first. That’s when I discovered Mongoose, a MongoDB library that simplified everything. Here’s a detailed breakdown of my journey from beginner to advanced with Mongoose and how you can follow along!

Step 1: Connecting to MongoDB

The first step in working with Mongoose is connecting your Node.js application to MongoDB. Initially, the idea of connecting to a database seemed complex, but Mongoose made it so intuitive.

const mongoose = require("mongoose");

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

What I did here:

  • mongoose.connect: Establishes a connection to the database.

  • Options like useNewUrlParser and useUnifiedTopology ensure a smooth connection.

Seeing the message “Connected to MongoDB!” in my Vs code console was such a motivating moment for me—it signified the first step toward mastering backend development.

When I want to store data in database in MySql I created a table:

CREATE TABLE User (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    age INT CHECK (age > 0),
    email VARCHAR(255) UNIQUE NOT NULL CHECK (email LIKE '%@gmail.com')
);

So, like that I need to create a table in MongoDB also:

Step 2: Creating Schemas and Models

Mongoose introduces schemas to structure data, which was fascinating because it brought some order to the flexibility of NoSQL.

Here’s an example of a schema for a User model:

const userSchema = new mongoose.Schema({
  name: { type: String, required: true },
  age: { type: Number, min: 18 },
  email: { type: String, unique: true },
});

const User = mongoose.model("User", userSchema);
  • Schema: Defines the structure and rules for the data.

  • Model: Provides an interface to interact with the MongoDB collection.

What I loved here was the ability to enforce rules, like making email unique and setting a minimum value for age. It gave me control while maintaining flexibility.

Step 3: CRUD Operations Simplified

CRUD (Create, Read, Update, Delete) operations are the backbone of any application, and Mongoose made these tasks effortless:

Create a User

insert into User

values(“Sam”, 22, Sam@gmail.com)
const user = new User({ name: "John", age: 25, email: "john@example.com" });
await user.save();
console.log("User saved:", user);

Read Users

select * from User
where age >= 18;
const users = await User.find({ age: { $gte: 18 } });
console.log("Adult users:", users);

Update a User

MySql:

UPDATE User 
SET age = 30 
WHERE name = 'John';
await User.updateOne({ name: "John" }, { $set: { age: 30 } });
console.log("User updated!");

Delete a User

MySQL:

delete from User
where name="John";

MongoDB:

await User.deleteOne({ name: "John" });
console.log("User deleted!");

These simple methods allowed me to interact with my database effortlessly while focusing more on building features.

Step 4: Data Validation and Middleware

As I built more complex applications, I realized the importance of validating data before saving it. Mongoose validations came to my rescue:

Here Just like MySQL I created MongoDB Schema:

Adding Validations

MySQL:

CREATE TABLE User (
    id INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(255) NOT NULL UNIQUE,
    CONSTRAINT chk_email_format CHECK (email REGEXP '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$')
);

MongoDB:

const userSchema = new mongoose.Schema({
  email: {
    type: String,
    required: [true, "Email is required!"],
    match: [/.+\@.+\..+/, "Enter a valid email!"],
  },
});

This ensures:

  1. Required fields: Throws an error if email is missing.

  2. Custom validation: Ensures the email matches a proper format.

Middleware for Automation

Middleware was a turning point for me. It allowed me to execute logic automatically at specific stages, like hashing passwords before saving:

userSchema.pre("save", async function (next) {
  if (this.isModified("password")) {
    this.password = await bcrypt.hash(this.password, 10);
  }
  next();
});

Middleware ensured that every user’s password was securely hashed—a crucial step for building secure applications.

Step 5: Advanced Features

Once I was comfortable with the basics, I started exploring Mongoose’s advanced features.

Virtuals

Virtual fields let you define properties that don’t get stored in the database but are derived from existing data.

userSchema.virtual("fullName").get(function () {
  return `${this.firstName} ${this.lastName}`;
});

Population

Population enables you to reference documents from other collections, making relational-like data modeling possible:

const postSchema = new mongoose.Schema({
  title: String,
  author: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
});
const Post = mongoose.model("Post", postSchema);

const posts = await Post.find().populate("author");
console.log(posts);

This was game-changing when I needed to build relationships between different models.

Indexes

Indexes improve query performance. Mongoose allows you to define them easily:

userSchema.index({ email: 1 });

What I Learned

Mongoose transformed how I approached database management coming from SQL I enjoyed exploring MongoDB. From handling simple CRUD operations to implementing advanced features like validations, middleware, and population, every step made me more confident in working with MongoDB.

Key Takeaways:

  1. Learn one feature at a time—don’t rush.

  2. Use validations and middleware to catch issues early.

  3. Explore advanced features to unlock more possibilities.

Conclusion

Mongoose has been a game-changer in my journey as a Node.js developer. Its intuitive methods, validations, and powerful features make MongoDB a breeze to work with.

If you’re just starting out, take it step by step. Each concept builds on the previous one, and before you know it, you’ll be handling databases like a pro!

Have you started using Mongoose yet? Share your experiences or questions below, and let’s grow together! 🚀

Happy coding! 🙌

Connect with me on Twitter, LinkedIn and GitHub for updates and more discussions