Data Validation With Mongoose in Node.js

How to validate our data before saving it into MongoDB with mongoose library

Photo by fabio on Unsplash

1.Introduction

Hello, my dev friends !!!!

Creating functions and procedures to save data into databases is an everyday task for software developers, but how we are sure about the actual stored data has the form that we want ???

Saving clean and proper formatted data increases the overall data quality plus our application is more secure.

In this story, we’ll learn how to validate our data before storing it into MongoDB with mongoose library.

Mongoose is a great object modeling tool for MongoDB and node.js, it is trusted by millions of developers, has nearly 800,000 weakly downloads at npm and 20.4k stars at GitHub.

2. About Validation In Mongoose

Mongoose add validation rules at schemas(models) and has 2 types of rules :

Built-in rules Custom rules

Validation is a middleware and Mongoose runs validation before saving the model into a database.

3.Built-in Validation Rules

Mongoose gives us a set of useful built-in validation rules such:

Required validator checks if a property is not empty. Numbers have min and max validators. Strings have enum , match , minlength , and maxlength validators.

Let’s create a new node.js project

mkdir validateModelMongoose

npm init -y

npm i mongoose

Create a new file with name product.js for our model

const mongoose = require("mongoose"); // create product schema let product = mongoose.Schema({ name: { type: String, required: [true, 'Product name required'] }, category: { type: String, required: [true, 'Category required'], enum: ['Keyboard', 'Computer'] }, code: { type: String, required: [true, 'Code required'], minlength:[5,'Minimun code length 5 characters'] }, quantity: { type: Number, required: [true, 'Quantity required'], min: [0, 'Minimun quantity is zero'] } }); module.exports = mongoose.model("product", product);

At the above code, we have created a product model with some built-in validators.

Let’s explain what’s going on with built-in validators

Required validator takes an array with 2 items, first a boolean var and a message to return the validation if it fails.

required: [true, 'Product name required']

Enum validator takes an array with items to check if the property is equal with one of the given array items.

enum: ['Keyboard', 'Computer']

Min validator takes an array with 2 items, first a number to set a minimum value and a message to return the validation if it fails.

Max, minlength and maxlegth works as same as min validator.

min: [0, 'Minimun quantity is zero']

Create an index.js file and paste the following code

'use strict' var mongoose = require("mongoose"); let PRODUCT = require("./product"); let db = mongoose.connection; //connect with local mongodb mongoose.connect("mongodb://localhost:27017/products", { useNewUrlParser: true, useUnifiedTopology: true });

//create a new product var product = new PRODUCT(); product.name = ''; product.category = 'Computers'; product.code = '123'; product.quantity = '-5'; //Save Product to Database product.save(function (error,document) { //check for errors let errors = getErrors(error); //Send Errors to browser console.log(errors); }); function getErrors(error) { let errorArray = []; if (error) { if (error.errors['category']) { console.log(error.errors['category'].message) errorArray.push('category'); } if (error.errors['name']) { console.log(error.errors['name'].message) errorArray.push('name'); } if (error.errors['code']) { console.log(error.errors['code'].message) errorArray.push('code'); } if (error.errors['quantity']) { console.log(error.errors['quantity'].message) errorArray.push('quantity'); } } else { console.log('No Errors Product Saved Succefully') } return errorArray; };

Run the code and check for the errors

node index.js

Example output

`Computers` is not a valid enum value for path `category`.

Product name required

Minimun code length 5 characters

Minimun quantity is zero

[ 'category', 'name', 'code', 'quantity' ]

The above code shows us that mongoose called validation middleware before saving it to the database and throw us the errors that have validated.

4.Custom Sync Validators

In this section, we’ll learn how to create our custom synchronize validators. Sync operations are blocking the event queue that’s why we have to use it wisely.

Products code usually have a format such as XXXX-XXXX-XXXX, to check if a product code has the proper form we’ll create a custom validator with regex to check the format.

Go to your model and change your code property with the following code

code: { type: String, required: [true, 'Code required'], //sync validation validate: { validator: function (v) { //regex product code must have XXXX-XXXX-XXXX format //return true to pass the validation //return false to fail the validation return (/\d{4}-\d{4}-\d{4}/.test(v)); },

//message to return if validation fails message: props => `${props.value} is not a valid code format!` }, required: [true, 'Code required'] }

Custom validators are located at code.validate and take 2 properties first a validator function that returns true(validation success) or false(validation fails) and a message to return if the validation fails.

Run your app

node index

// example output

123456 is not a valid code format!

5.Custom Async Validators

Last we’ll see how to implement async custom validators. We’ll change the sync custom validation to async.

To add async validation rules we have to implement at code.validate.validator a function that will return a Promise and resolve with true(validation success) or false(validation fails)

Go to your model and change your code property with the following code

code: { type: String, required: [true, 'Code required'], //async validation validate: { validator: function (v) { return new Promise(function (resolve, reject) { //regex product code must have XXXX-XXXX-XXXX format //resolve(true) pass valitation //resolve(false) fail valitation resolve(/\d{4}-\d{4}-\d{4}/.test(v)); }); }, message: props => `${props.value} is not a valid code format!` } }

The above code shows how to create an async custom validator.

Run your app

node index.js

//example output

123 is not a valid code format!

[ 'code' ]

6.Conclusion

Mongoose offers us simple, clean, and quick ways to validate our models before saving into MongoDB so it worth using these functionalities.

References