Node.js · Mongoose · MongoDB · Authentication
Understanding Mongoose Pre Hooks and Methods
Learn how Mongoose pre hooks and instance methods can keep Node.js and MongoDB model logic reusable and maintainable.

Table of Contents
1. Overview
In the world of Node.js and MongoDB, Mongoose is a powerful ODM (Object Data Modeling) library that makes managing data a breeze. Recently, I delved into the concept of pre hooks and methods in Mongoose, and I was pleasantly surprised by how much cleaner and more efficient my code became. In this post, I’ll share my experience, along with some practical examples, particularly focusing on implementing cryptography and access-tokens.
Understanding Mongoose Pre Hooks
Pre hooks in Mongoose allow you to execute some logic before a particular operation is performed on a document. This is particularly useful for tasks like validation, data manipulation, or even integrating cryptographic functions before saving sensitive data.
Setting Up a Basic Mongoose Schema
Let’s start by setting up a simple User schema:
import mongoose from 'mongoose';
import bcrypt from 'bcrypt';
const userSchema = new mongoose.Schema({
username: { type: String, required: true, unique: true },
password: { type: String, required: true },
});
// Pre hook for password hashing
userSchema.pre('save', async function (next) {
if (!this.isModified('password')) return next();
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
next();
});
const User = mongoose.model('User', userSchema);In the example above, we set up a pre hook that hashes the password before saving it to the database. The isModified check ensures that we only hash the password when it’s actually changed, avoiding unnecessary operations.
Implementing Methods
In addition to pre hooks, Mongoose allows us to define instance methods that can be called on documents. This can be useful for actions that are specific to a single document.
Adding an Instance Method for Password Verification
Let’s extend our User schema with a method to verify the password:
userSchema.methods.comparePassword = async function (candidatePassword) {
return await bcrypt.compare(candidatePassword, this.password);
};Using the User Model
Now, let’s see how we can use our User model with the pre hook and the instance method:
const mongoose = require('mongoose');
async function run() {
await mongoose.connect('mongodb://localhost:27017/mydatabase');
const newUser = new User({
username: 'testuser',
password: 'mySecurePassword',
});
await newUser.save();
// Password verification
const isMatch = await newUser.comparePassword('mySecurePassword');
console.log('Password match:', isMatch); // Should log: Password match: true
}Benefits of Using Pre Hooks and Methods
- Code Cleanliness: By encapsulating functionality within pre hooks and methods, your main application logic becomes cleaner and easier to read.
- Reusability: Instance methods can be reused across different parts of your application, promoting DRY (Don’t Repeat Yourself) principles.
- Separation of Concerns: Pre hooks allow you to separate logic that pertains to data integrity (like password hashing) from your business logic.
Conclusion
Incorporating pre hooks and methods into your Mongoose models can greatly enhance your application's architecture. Not only does it streamline your code, but it also makes implementing features like cryptography and access tokens far simpler.
If you haven’t explored Mongoose pre hooks and methods yet, I highly recommend diving in. You might just find that it transforms the way you write your code!
Happy coding! 🚀