Bird
Raised Fist0
Expressframework~10 mins

Mongoose middleware (pre/post hooks) in Express - Step-by-Step Execution

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Concept Flow - Mongoose middleware (pre/post hooks)
Define Schema
Attach pre-hook
Attach post-hook
Create Model
Call Model Method (e.g., save)
Run pre-hook
Execute original method
Run post-hook
Return result
This flow shows how Mongoose middleware hooks run before and after a model method like save, allowing code to run around database actions.
Execution Sample
Express
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({ name: String });
userSchema.pre('save', function(next) {
  console.log('Before save');
  next();
});
userSchema.post('save', function(doc) {
  console.log('After save', doc.name);
});
This code sets up a schema with pre and post save hooks that log messages before and after saving a user.
Execution Table
StepActionHook TypeHook Function OutputNext Step
1Call user.save()NoneN/ARun pre-save hook
2Run pre-save hookpreLogs 'Before save'Call original save method
3Execute original saveNoneUser saved to DBRun post-save hook
4Run post-save hookpostLogs 'After save <name>'Return from save()
5Return from save()NoneSave completeEnd
💡 All hooks run in order; save completes after post hook.
Variable Tracker
VariableStartAfter Step 2After Step 3After Step 4Final
user.name"Alice""Alice""Alice""Alice""Alice"
hookLog[]["Before save"]["Before save"]["Before save", "After save Alice"]["Before save", "After save Alice"]
Key Moments - 3 Insights
Why does the pre-hook call next()?
The pre-hook calls next() to tell Mongoose to continue running the original save method. Without next(), the save would stop (see execution_table step 2).
When does the post-hook run?
The post-hook runs after the original save method finishes successfully (see execution_table step 4). It receives the saved document.
Can pre-hooks modify data before saving?
Yes, pre-hooks can change document fields before calling next(), so the saved data can be altered (implied in step 2 before save).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table, what happens at step 3?
AThe post-save hook logs a message
BThe pre-save hook logs a message
CThe original save method runs and saves the user to the database
DThe save method returns without saving
💡 Hint
Check the 'Action' and 'Hook Type' columns at step 3 in the execution_table
At which step does the post-save hook log the user's name?
AStep 2
BStep 4
CStep 3
DStep 5
💡 Hint
Look for 'post' hook type and logging action in execution_table step 4
If the pre-hook did not call next(), what would happen?
AThe save method would not run and the user would not be saved
BThe post-hook would run immediately
CThe save method would run twice
DNothing would change
💡 Hint
Refer to key_moments about the importance of calling next() in pre-hooks
Concept Snapshot
Mongoose middleware hooks run code before (pre) or after (post) model methods.
Pre-hooks must call next() to continue the operation.
Post-hooks receive the result after the operation.
Use hooks to add logic around DB actions like save or remove.
Hooks run in order: pre -> original method -> post.
Full Transcript
Mongoose middleware allows you to run code before or after certain model methods like save. You define pre-hooks that run before the method and post-hooks that run after. The pre-hook must call next() to let Mongoose continue saving. The post-hook runs after the save completes and can access the saved document. This lets you add custom logic around database actions easily. The flow is: define schema, attach pre and post hooks, create model, call method, run pre-hook, run original method, run post-hook, then finish. This helps keep your code organized and reactive to data changes.

Practice

(1/5)
1. What is the main purpose of pre middleware in Mongoose?
easy
A. To connect to the MongoDB database
B. To run code after a database operation completes
C. To define the schema structure
D. To run code before a database operation like save or remove

Solution

  1. Step 1: Understand middleware timing

    Pre middleware runs before a database action, allowing preparation or validation.
  2. Step 2: Differentiate pre and post hooks

    Post middleware runs after the action, so pre is for before actions.
  3. Final Answer:

    To run code before a database operation like save or remove -> Option D
  4. Quick Check:

    Pre middleware = before action [OK]
Hint: Pre means before the action starts [OK]
Common Mistakes:
  • Confusing pre with post middleware
  • Thinking pre defines schema structure
  • Assuming pre connects to database
2. Which of the following is the correct syntax to add a pre-save hook in Mongoose?
easy
A. schema.on('save', function(next) { /* code */ next(); });
B. schema.pre('save', function(next) { /* code */ next(); });
C. schema.before('save', function() { /* code */ });
D. schema.post('save', function(next) { /* code */ next(); });

Solution

  1. Step 1: Recall Mongoose middleware method names

    Mongoose uses pre and post methods for middleware, not before or on.
  2. Step 2: Check syntax for pre-save hook

    The correct syntax is schema.pre('save', function(next) { ... next(); }); to run code before saving.
  3. Final Answer:

    schema.pre('save', function(next) { /* code */ next(); }); -> Option B
  4. Quick Check:

    Use schema.pre for pre hooks [OK]
Hint: Use schema.pre('event', fn) for pre hooks [OK]
Common Mistakes:
  • Using schema.post instead of schema.pre for pre hooks
  • Using non-existent methods like before or on
  • Forgetting to call next() in middleware
3. Given this Mongoose pre-save middleware, what will be the value of doc.updatedAt after saving?
schema.pre('save', function(next) {
  this.updatedAt = new Date();
  next();
});
medium
A. Undefined because updatedAt is not set in schema
B. The date when the document was created
C. The current date and time when save is called
D. An error because next() is missing

Solution

  1. Step 1: Understand pre-save middleware effect

    The middleware sets this.updatedAt to the current date before saving.
  2. Step 2: Confirm middleware runs before save

    Since it runs before save, the document's updatedAt will be updated to the current time.
  3. Final Answer:

    The current date and time when save is called -> Option C
  4. Quick Check:

    Pre-save sets updatedAt = now [OK]
Hint: Pre-save runs before saving, so updatedAt is current time [OK]
Common Mistakes:
  • Assuming updatedAt is undefined without schema field
  • Confusing createdAt with updatedAt
  • Thinking next() is missing causing error
4. What is wrong with this Mongoose middleware code?
schema.pre('remove', (next) => {
  console.log('Removing', this._id);
  next();
});
medium
A. Arrow function does not bind 'this', so 'this' is undefined inside middleware
B. Missing call to next() to continue middleware chain
C. Using 'remove' event is not supported in Mongoose
D. Middleware must be post, not pre, for remove

Solution

  1. Step 1: Check function type in middleware

    Mongoose middleware requires normal functions to bind this to the document.
  2. Step 2: Identify arrow function issue

    Arrow functions do not bind this, so this will be undefined inside the middleware.
  3. Final Answer:

    Arrow function does not bind 'this', so 'this' is undefined inside middleware -> Option A
  4. Quick Check:

    Use normal functions for middleware to access this [OK]
Hint: Use function() not arrow to access this in middleware [OK]
Common Mistakes:
  • Using arrow functions in middleware
  • Forgetting to call next() in async middleware
  • Thinking remove event is unsupported
5. You want to log a message after a document is saved and also update a cache. Which Mongoose middleware setup is correct?
hard
A. Use schema.post('save', function(doc) { console.log('Saved:', this._id); updateCache(this); });
B. Use schema.pre('save', function(doc) { console.log('Saved:', this._id); updateCache(this); });
C. Use schema.post('save', (doc) => { console.log('Saved:', this._id); updateCache(this); });
D. Use schema.pre('save', (doc) => { console.log('Saved:', this._id); updateCache(this); });

Solution

  1. Step 1: Identify when to run logging and cache update

    Logging and cache update should happen after saving, so use post middleware.
  2. Step 2: Choose correct function syntax

    Post middleware receives the saved document as first argument; use normal function to access this if needed.
  3. Final Answer:

    Use schema.post('save', function(doc) { console.log('Saved:', this._id); updateCache(this); }); -> Option A
  4. Quick Check:

    Post-save + normal function for logging/cache [OK]
Hint: Use post-save with normal function for after-save tasks [OK]
Common Mistakes:
  • Using pre instead of post for after-save tasks
  • Using arrow functions losing this context
  • Not passing doc argument in post middleware