Sling Academy
Home/Node.js/Mongoose Data Validation Examples

Mongoose Data Validation Examples

Last updated: December 30, 2023

Overview

Validating data before it is saved to a database is a critical aspect of web development. Mongoose, a Node.js object data modeling (ODM) library for MongoDB, includes built-in validation mechanisms that enhance the robustness and reliability of your application by ensuring only valid data is stored. This article aims to guide you through a comprehensive understanding of Mongoose data validation using various code examples demonstrating how to implement validation at different complexity levels. From simple mandatory fields to custom validator functions and asynchronous validation, we’ll explore it all.

Basic Validation

Let’s start by exploring the simplest form of validation in Mongoose which is declaring a field as required.

const mongoose = require('mongoose');
const { Schema } = mongoose;

const userSchema = new Schema({
  username: { type: String, required: true },
  email: { type: String, required: true, unique: true }
});

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

In the snippet above, the username and email fields are marked as required, and the email is also specified to be unique so duplicate entries are prevented.

Type Validation

In Mongoose, each schema path can define its type and optional constraints like minimum or maximum values for numbers.

const productSchema = new Schema({
  price: { type: Number, required: true, min: 0 },
  stock: { type: Number, default: 0, min: 0 }
});

const Product = mongoose.model('Product', productSchema);

The price attribute must be a positive number, including zero, as the min validator enforces it.

String Validation

Mongoose provides validators specifically for string data types like enum, match, minlength, and maxlength.

const bookSchema = new Schema({
  title: { type: String, required: true, trim: true },
  status: { type: String, enum: ['AVAILABLE', 'OUT_OF_STOCK', 'DISCONTINUED'], required: true },
  isbn: { type: String, match: /[0-9-]{10,13}/ }
});

const Book = mongoose.model('Book', bookSchema);

Above, books can only have a status that is part of a predefined set of values. Also, the isbn field will only accept a string that matches the specified regular expression pattern for ISBNs.

Custom Validation

For more complex validation rules, you can also define custom validator functions. They allow you to specify your own logic for data validation.

const userSchema = new Schema({
  website: {
    type: String,
    validate: {
      validator: function(v) {
        return /^(https?:\/\/)?(www\.)?[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,6}(:[0-9]{1,5})?(\/.)?$/.test(v);
      },
      message: props => `${props.value} is not a valid URL!`
    }
  }
});

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

In this schema, a custom validator ensures the website field must be a valid URL format and provides a custom error message if the validation fails.

Asynchronous Validators

In scenarios where you need to make a database call or an asynchronous request during validation, Mongoose supports asynchronous custom validators.

const uniqueEmailValidator = async (email) => {
  const existingUser = await User.findOne({ email });
  return !existingUser;
};

const userSchema = new Schema({
  email: {
    type: String,
    validate: [uniqueEmailValidator, 'That email address is already taken.'],
    lowercase: true,
    trim: true,
  }
});

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

Here, the validator function checks whether an email address is already in use by querying the database and validating the result asynchronously.

Conclusion

Mongoose data validation is a powerful feature that can greatly reduce errors and data corruption within your application. By using built-in validators for commons checks and custom validators for more complex scenarios, you can build robust persistence layers with comprehensive data rules. The provided examples range from basic mandatory field requirements to advanced, asynchronous and custom validators, offering a toolbox for ensuring the integrity of your application’s data. Validation best practices include thoughtful schema design and combining server-side validation logic with client-side validation.

Next Article: Resolving the Mongoose Buffering Timed Out Error in Node.js

Previous Article: How to create multifield indices in Mongoose

Series: Mongoose.js Tutorials

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates