Sling Academy
Home/Node.js/How to validate strings in Mongoose

How to validate strings in Mongoose

Last updated: December 30, 2023

Overview

Validation is a critical aspect of dealing with model data in MongoDB when using Mongoose. Mongoose provides an array of validation options that you can utilize to ensure data integrity right out-of-the-box. In this guide, we will focus exclusively on string validation, looking at fundamental techniques before progressing to more advanced patterns and custom validation utilities. We will explore how to apply different types of validations on string fields such as required fields, length, matching patterns, and custom-validation functions. For this tutorial, it is assumed that the reader possesses basic knowledge of Node.js, Express, and Mongoose setup.

Before diving into the code examples, let’s refresh on structuring models in Mongoose. Models are defined through the Schema interface, with various field types and options. Adding validation is then as simple as defining the schema with validation rules implemented directly or through middleware.

Note: All examples provided are intended to be used within an async environment, taking advantage of modern JavaScript and Node.js features like arrow functions, async/await, and ES modules.

Basic Validation

Let’s begin with the simplest form of validation in Mongoose: the required validator, which ensures that a given string field is not empty.

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

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

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

async function createUser(username) {
  try {
    const user = new User({ username });
    await user.save();
    console.log('User created:', user);
  } catch (error) {
    console.error('Error creating user:', error.message);
  }
}

// Example usage:
createUser('').catch(console.error);

This will throw a validation error when attempting to save a user with an empty username.

Length Validation

Restricting the length of a string can be easily achieved using the `minlength` and `maxlength` options.

userSchema.path('username').validate({
  minlength: 3,
  maxlength: 30
});

This ensures that the username must be between 3 to 30 characters long.

Pattern Matching

We can enforce patterns such as only alphanumeric usernames using regular expressions.

userSchema.path('username').validate({
  validator: function(v) {
    return /^[a-zA-Z0-9]+$/g.test(v);
  },
  message: props => `${props.value} is not a valid username!`
});

This username validation checks for only alphanumeric characters and will reject any string that does not meet the regular expression.

Custom Validators

In Mongoose, we have the capacity to define custom validation functions, which cater to more nuanced validation logic.

userSchema.path('username').validate({
  validator: function(v) {
    return v.length >= 3 && /^[a-zA-Z0-9]+$/g.test(v);
  },
  message: 'Username must be at least 3 characters long and contain only alphanumeric characters.'
});

This is a complex validator that combines length and pattern checks into a single custom validator. The beauty of custom validators lies in their versatility: they can be made as simple or intricate as your application requires.

Asynchronous Custom Validators

For validations that require database checks or other asynchronous operations, Mongoose provides an option to specify validators as asynchronous functions.

userSchema.path('email').validate({
  validator: async function(v) {
    const userCount = await User.countDocuments({ email: v }).exec();
    return userCount === 0;
  },
  message: 'The email already exists in the system.'
});

This code sets up an asynchronous validator that checks whether an email address is already registered in the database. If so, the validation fails, informing the user that the email already exists in the system.

Conclusion

In summary, string validation in Mongoose is straightforward but highly powerful. It starts with basic requirements and can be extended to complex scenarios with custom, asynchronous functions that accommodate any validation logic or data integrity need. Correct implementation of validation logic helps in maintaining clean and reliable data, aids in preventing common data-related issues, and certainly, assists in delivering a robust user experience. Remember that our guide aims to assist in the development of efficient applications by utilizing the Mongoose ORM to its full potential for string validation.

Next Article: How to Validate Email Addresses in Mongoose

Previous Article: Using Mixed Schema Type 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