Mongoose is a popular Object Document Mapper (ODM) for MongoDB in Node.js. This tutorial shows how to define schemas, create models, and perform CRUD operations with Mongoose and Express, with examples for installation, configuration, queries, sorting, and pagination.

What is Mongoose ODM?

Mongoose is MongoDB's Object Document Mapper ( ODM ) designed to work in an asynchronous environment. MongoDB stores data in JSON-like documents, and Mongoose provides a schema-based abstraction layer that simplifies working with MongoDB in Node.js applications. Using Mongoose, developers can map JSON documents to full JavaScript Objects with data validation, schemas, middleware, and business logic.

Mongoose provides a comprehensive set of features including schema-based solutions, type casting, validation rules, query building, business logic hooks, and many other out-of-the-box features that make working with MongoDB more productive.

In traditional SQL databases, developers use ORM (Object Relational Mapping), but in NoSQL databases like MongoDB, developers use ODM (Object Document Mapper) for the same purpose.

Key Features of Mongoose

  • Schema Validation: Define data structure and enforce validation rules
  • Type Casting: Automatic type conversion for document fields
  • Middleware/Hooks: Pre and post hooks for document operations
  • Query Building: Chainable query API for flexible data retrieval
  • Virtuals: Computed properties not stored in MongoDB
  • Population: Automatic reference resolution between documents
  • Indexing: Support for MongoDB indexes to optimize queries
  • Promise Support: Native promises and async/await compatibility

Install Mongoose

Mongoose is available on npm (Node Package Manager) as the mongoose package. You can easily install it using npm and include the mongoose module in your main application file.

npm i mongoose

This command installs Mongoose and its dependencies in your Node.js project. Mongoose is the recommended way to interact with MongoDB in Node.js applications.

Configure Mongoose Connection

Configuring Mongoose requires establishing a connection to your MongoDB instance. Below are examples for both modern (Mongoose 6+) and legacy (Mongoose 5 and below) versions.

Promise-based API for Mongoose 6 and above

Modern Mongoose versions use async/await and promises for better code readability and error handling.

            /*dao.js*/
    // Connection setup with Mongoose 6+
    const mongoose = require('mongoose');
    
    main().catch(err => console.log(err));
    
    async function main() {
      await mongoose.connect('mongodb://127.0.0.1:27017/node');
    
      // use `await mongoose.connect('mongodb://user:password@127.0.0.1:27017/test');` if authentication is enabled
    
      console.log("Database Connected Successfully");
    }
   

Callback-based API for Mongoose 5 and below

Legacy Mongoose versions use callback-based connection handling. While still functional, promise-based approach is recommended for new projects.

            /*dao.js*/
 const mongoose=require('mongoose');
 
 mongoose.connect('mongodb://127.0.0.1:27017/node').then(() => console.log('Connected to MongoDB!'));

 const db=mongoose.connection;

 db.on('error', function (err) { throw err });

 db.once('open', function callback() {
    console.log('connected!');
    db.close();
});

Run Mongoose Connection

Execute your connection file to test the MongoDB connection and verify that Mongoose is properly configured.

Database Connected Successfully

node src/dao

Creating Mongoose Schemas

Mongoose Schema is a blueprint that defines the structure, field types, and validation rules for MongoDB documents. Each schema contains key-value pairs that specify field names and their configurations. Schemas enforce data consistency and provide type safety.

Supported Schema Field Types

Mongoose supports various data types for schema fields, allowing you to model different kinds of data:

  1. String: Text data
  2. Number: Integer and decimal values
  3. Date: Date and time values
  4. Buffer: Binary data
  5. Boolean: True/false values
  6. ObjectId: References to other MongoDB documents
  7. Array: Collections of values or nested documents
  8. Decimal128: High-precision decimal numbers
  9. Map: Key-value pairs with dynamic keys
 
const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Define a basic schema with field types
const CarSchema = new Schema({
    _id: mongoose.ObjectId,
    name: String,
    type: String,
    price: Number
}, {collection: "cars"});

Schema with Validation Rules

Mongoose allows you to add validation rules to schema fields. Validation ensures data integrity by enforcing constraints on the data being saved to MongoDB.

 
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
  
// Schema with comprehensive validation rules
const CarSchema = new Schema({
  _id: mongoose.ObjectId,
  name: {
    type: String,
    required: true,        // Field is mandatory
    unique: true,          // Each value must be unique
    trim: true,            // Remove whitespace
    minlength: 2,          // Minimum string length
    maxlength: 100         // Maximum string length
  },
  type: {
    type: String,
    required: true,
    enum: ['sedan', 'suv', 'hatchback', 'coupe']  // Only allow specific values
  },
  price: {
    type: Number,
    required: true,
    min: 0,                // Minimum value
    max: 10000000          // Maximum value
  },
  year: {
    type: Number,
    min: 1900,
    max: new Date().getFullYear()
  }
}, {collection: "cars"});

Creating Mongoose Models

The next step after defining a schema is to create a model from that schema using mongoose.model(). A model is a constructor that compiles your schema definition and represents a MongoDB collection. Each model instance represents a document in that collection.

The optional second configuration object uses the collection property to specify the MongoDB collection name. If you don't specify a collection name, Mongoose automatically pluralizes the model name.


const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Define the schema
const CarSchema = new Schema({
    _id: mongoose.ObjectId,
    name: { type: String, required: true, unique: true },
    type: { type: String, required: true },
    price: { type: Number, required: true },
    date: { type: Date, default: Date.now },
}, {collection: "cars"}); 

// Compile schema to model
const Car = mongoose.model("Car", CarSchema); 

Creating Model Instances for Database Operations

After defining a model, you can create instances of that model to perform database operations. Each instance represents a document that can be saved to MongoDB.


const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Define schema
const CarSchema = new Schema({
    _id: mongoose.ObjectId,
    name: { type: String, required: true },
    type: { type: String, required: true },
    price: { type: Number, required: true },
    date: { type: Date, default: Date.now },
}, {collection: "cars"}); 

// Create model
const Car = mongoose.model("Car", CarSchema); 

// Create an instance of the model
const newCar = new Car({
    _id: new mongoose.Types.ObjectId(),
    name: 'Honda Civic',
    type: 'sedan',
    price: 1500000
});

Insert Data into MongoDB Collections

To persist data to MongoDB, use the model.save() method on a model instance. This method writes the document to the database collection. The example below demonstrates inserting car data into a 'cars' collection.

    /*dao.js - Complete example of inserting documents*/
const mongoose = require('mongoose');

// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/cars', {
    useNewUrlParser: true,
    useUnifiedTopology: true
});

const db = mongoose.connection;

const Schema = mongoose.Schema;

// Define the car schema with validation
const CarSchema = new Schema({
    _id: mongoose.ObjectId,
    name: { type: String, required: true },
    type: { type: String, required: true },
    price: { type: Number, required: true },
    date: { type: Date, default: Date.now }
}, {collection: 'suzuki'});

// Create model from schema
const Car = mongoose.model("Car", CarSchema);

// Create a new car document
const newCar = new Car({
  _id: new mongoose.Types.ObjectId(),
  name: "Swift",
  type: "hatchback",
  price: 800000
});

// Handle database connection events
db.on('error', function(err){ throw err }); 

db.once('open', function() {
   console.log('Database connected!');

   // Save the document to database
   newCar.save()
   .then(savedCar => {
       console.log("Data saved successfully:", savedCar);
       res.status(200).send("Data saved successfully");
   })
   .catch(error => {
       console.error("Error saving data:", error);
       res.status(400).send("Error saving data");
   });
});     

Execute Insert Operation

Swift saved to Suzuki collection successfully.

node src/dao

Read Data from MongoDB Collections

To retrieve documents from MongoDB, use the model.find() method. You can search for documents matching specific criteria and retrieve all matching results. This example demonstrates querying the 'cars' collection.

    /*dao.js - Query example*/
const mongoose = require('mongoose');

mongoose.connect('mongodb://localhost:27017/cars', {
    useNewUrlParser: true,
    useUnifiedTopology: true
});

const db = mongoose.connection;

db.on('error', function (err) { throw err }); 

db.once('open', function() {
   console.log('Mongoose connected!');

   const Schema = mongoose.Schema;

   const CarSchema = new Schema({
    _id: mongoose.ObjectId,
    name: String,
    type: String,
    price: Number,
   }, {collection: 'cardata'});

  const Car = mongoose.model("Car", CarSchema);

  // Find all cars with name 'Swift'
  Car.find({name: "swift"})
  .then(results => {
      console.log("Found cars:", results);
  })
  .catch(err => {
      console.error("Query error:", err);
  });

  // Legacy callback-based approach (not recommended)
  /*
  Car.find({name:"swift"}, (err, data) => {
      if(err){
          console.error(err);
      } else {
          console.log(data);
      }
  });
  */
});

Query Output


Mongoose connected!
[
  {
    _id: 5eb81a2fbe672314a543269e,
    name: 'swift',
    type: 'hatchback',
    price: 800000
  }
]
node src/dao

Query Specific Fields Only

You can use MongoDB's field projection to retrieve only specific fields from matching documents, reducing data transfer and improving performance. Use the select() method or projection object.


// Method 1: Using select()
Car.find({type: "hatchback"})
.select('name type -_id')  // Include name and type, exclude _id
.then(results => console.log(results))
.catch(err => console.error(err));

// Method 2: Using projection object
Car.find({type: "hatchback"}, {name: 1, type: 1, _id: 0})
.then(results => console.log(results))
.catch(err => console.error(err));

Projection Output


Mongoose connected!
[
  {
    name: 'swift',
    type: 'hatchback'
  }
]
node src/dao

Limit Query Results for Pagination

Use the limit() method to restrict the number of documents returned by a query. This is essential for pagination and improving query performance when working with large datasets.


// Limit results to 2 documents
Car.find({type: "hatchback"})
.limit(2)
.then(results => console.log(results))
.catch(err => console.error(err));

Limit Query Output


Mongoose connected!
[
  {
    _id: 5eb81a2fbe672314a543269e,
    name: 'swift',
    type: 'hatchback'
  },
  {
    _id: 5eb5378791fc73f290f38252,
    name: 'baleno',
    type: 'hatchback'
  }
]
node src/dao

Sort Query Results in Ascending or Descending Order

The sort() method orders query results by a specific field. Use 1 for ascending order (A-Z, 0-9) and -1 for descending order (Z-A, 9-0).


// Sort cars by name in ascending order
Car.find({})
.sort({name: 1})  // 1 = ascending, -1 = descending
.then(results => console.log(results))
.catch(err => console.error(err));

// Sort by price in descending order
Car.find({})
.sort({price: -1})
.then(results => console.log(results));

Sort Query Output


Mongoose connected!
[
  {
    _id: 5eb5378791fc73f290f38252,
    name: 'baleno',
    type: 'hatchback'
  },
  {
    _id: 5eb81a2fbe672314a543269e,
    name: 'swift',
    type: 'hatchback'
  }
]
node src/dao

Frequently Asked Questions

What is Mongoose?

Mongoose is an ODM (Object Document Mapper) that provides a schema-based solution to model application data for MongoDB in Node.js.

How do I install Mongoose?

Install via npm with npm i mongoose and require it in your Node.js app using const mongoose = require('mongoose');.