0
0
MongodbHow-ToBeginner · 4 min read

How to Use Middleware in Mongoose: Syntax and Examples

In Mongoose, you use middleware by defining pre or post hooks on a schema with schema.pre() or schema.post(). These hooks run functions before or after events like save, remove, or find to add custom logic.
📐

Syntax

Mongoose middleware is defined on a schema using schema.pre() for actions before an event, and schema.post() for actions after an event. You specify the event name like save or remove, and provide a callback function that runs at that time.

The callback can be asynchronous and receives a next function to continue the operation.

javascript
schema.pre('save', function(next) {
  // code to run before saving
  next();
});

schema.post('remove', function(doc) {
  // code to run after removing
});
💻

Example

This example shows how to use a pre-save middleware to automatically set a timestamp before saving a document, and a post-remove middleware to log when a document is deleted.

javascript
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  name: String,
  createdAt: Date
});

// Pre-save middleware to set createdAt
userSchema.pre('save', function(next) {
  if (!this.createdAt) {
    this.createdAt = new Date();
  }
  next();
});

// Post-remove middleware to log deletion
userSchema.post('remove', function(doc) {
  console.log(`User ${doc.name} was removed.`);
});

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

async function run() {
  await mongoose.connect('mongodb://localhost:27017/testdb');

  const user = new User({ name: 'Alice' });
  await user.save();
  console.log('User saved:', user);

  await user.remove();

  await mongoose.disconnect();
}

run();
Output
User saved: { _id: ..., name: 'Alice', createdAt: 2024-06-01T... } User Alice was removed.
⚠️

Common Pitfalls

  • Forgetting to call next() in pre middleware causes the operation to hang.
  • Using arrow functions (() => {}) for middleware breaks this binding; always use regular functions.
  • Not handling asynchronous code properly can cause unexpected behavior; use async functions or call next() after async operations.
javascript
/* Wrong: arrow function loses 'this' context */
schema.pre('save', (next) => {
  console.log(this); // undefined
  next();
});

/* Right: regular function keeps 'this' */
schema.pre('save', function(next) {
  console.log(this); // document being saved
  next();
});
📊

Quick Reference

Middleware TypeWhen It RunsExample EventNotes
PreBefore an eventsave, remove, validateCall next() to continue
PostAfter an eventsave, remove, findReceives document or result
QueryBefore/after queriesfind, updateUse for query middleware
AggregateBefore/after aggregationaggregateUse for aggregation middleware

Key Takeaways

Use schema.pre() for middleware before events and schema.post() for after events.
Always use regular functions, not arrow functions, to access the document with this.
Call next() in pre middleware to avoid hanging operations.
Middleware can be async; use async/await or call next() after async work.
Middleware works on schema level to add reusable logic for database operations.