Contents
Pre and post middleware hooks is a very useful feature in Mongoose and provides a lot of flexibility during database operations like query, create, remove etc. Pre and post hooks are functions that are executed before or after a particular action that you specify. These hooks get triggered whenever you perform an operation with your database.
Types of Middleware
Mongoose has 4 types of middleware: document middleware, model middleware, aggregate middleware, and query middleware.
Document | Query | Aggregate | Model |
---|---|---|---|
validate | count | aggregate | insertMany |
save | deleteMany | ||
remove | deleteOne | ||
updateOne | find | ||
deleteOne | findOne | ||
init* | findOneAndDelete | ||
findOneAndRemove | |||
findOneAndUpdate | |||
remove | |||
update | |||
updateOne | |||
updateMany |
*init hooks are synchronous
Note: If you specify schema.pre('remove')
, Mongoose will register this middleware for doc.remove()
by default. If you want to your middleware to run on Query.remove()
use schema.pre('remove', { query: true, document: false }, fn)
.
Note: Unlike schema.pre('remove')
, Mongoose registers updateOne
and deleteOne
middleware on Query#updateOne()
and Query#deleteOne()
by default. This means that both doc.updateOne()
and Model.updateOne()
trigger updateOne
hooks, but this refers to a query, not a document. To register updateOne
or deleteOne
middleware as document middleware, use schema.pre('updateOne', { document: true, query: false })
.
Note: The create()
function fires save()
hooks.
Defining middlewares
- use normal callback with next parameter
The next
parameter is a function provided to you by mongoose to have a way out, or to tell mongoose you are done and to continue with the next step in the execution chain. Also it is possible to pass an Error
to next
it will stop the execution chain.
|
|
- use async callback
Here the execution chain will continue once your async
callback has finished. If there is an error and you want to break/stop execution chain you just throw
it
|
|
Note 1:- You must add all middleware and plugins before calling mongoose.model().
Note 2:- Remember we cannot use arrow function inside pre hooks as arrow function are poor binding functions.
Understanding Middlewares with an example
Let us define a User
schema as below:
|
|
In the above schema;
- a
pre hook
to validate whether the providedusername
contains only alphanumberic characters - a
pre hook
to generate hash of the user password - a
post hook
to notify/send email - a
pre hook
added postmongosse.model()
Run the below code:
|
|
You should see output as below and I guess the output is self-explanatory:
|
|
The sample code is checked into mongoose-hooks on github.
Use Cases
Pre-hooks can be utilized in a variety of scenarios, such as custom validations, generating hash password etc. You can also use them when you have a field named say "archived"
in your schema and you wish to exclude all archived documents in each "find"
call. Including a filter for "archived: false"
in every "find"
call may be cumbersome and error-prone. In such cases, pre-hooks can serve as query middleware to simplify the process. For instance, a simple pre-hook on the "find"
method in Mongoose can modify the query and add an extra filter, which will be applied to all subsequent "find"
queries for that model.
Another use case can be to add additional field say last_updatedMS
by default which saves epoch timestamp value on every update
operation.
Hooks have a multitude of use cases depending on your application and I hope you can identify potential use cases for your own application.
Conclusion
I hope that in this article, you have gained an understanding of how and when to utilize pre and post hooks in mongoose, as well as the benefits they provide in comparison to writing repetitive logic for actions performed on collection documents.
By implementing these hooks, we can reduce the amount of code we need to write, resulting in a smaller potential for bugs. Additionally, we can alleviate the mental burden of having to remember to execute certain logic before or after a method each time. There are various other use cases for pre and post middleware hooks, and their execution before the method they are hooked onto makes them a versatile tool.
✨ Thank you for reading and I hope you find it helpful. I sincerely request for your feedback in the comment’s section.