N N
N N

Reputation: 1638

How to reuse a pre middleware function in mongoose

I need to reuse one of pre middleware functions in another pre middleware, for that I extracted a function like so:

async function encryptPassword(next) {
    if (!this.isModified('password')) {
        return next();
    }
    this.password = await bcrypt.hash(this.password, 5);
    this.passwordChangedAt = new Date();
    next();
}

UserSchema.pre('save', encryptPassword);

UserSchema.pre("findOneAndUpdate", encryptPassword);

But I am getting an error saying that this.isModified is not a function, I assume that this is referring to something else. How to fix this?

Upvotes: 2

Views: 187

Answers (1)

Gynteniuxas
Gynteniuxas

Reputation: 7103

I dived into these pre/post hooks with a help of debugger & docs and I have found several things (these apply to both pre and post):

Using save hook will mean that this refers a document itself. Thus, you can update its fields, call methods like isModified, etc. You should not have any issues with the above method.

However, findOneAndUpdate hook will mean that this refers to a query instead of document. And Query object will not have documents or their inherited methods (like isModified).

I checked with debugger and can confirm it is the case (up-to-date with documentation).

A list of hooks: https://mongoosejs.com/docs/middleware.html#types-of-middleware

You will see that only the following hooks allow to modify documents:

validate
save
remove
updateOne
deleteOne
init (note: init hooks are synchronous)

And all others will not. It seems this is intentional (https://github.com/Automattic/mongoose/issues/964).

To solve an issue with findOneAndUpdate, it seems the only way (most closely resembling) is to rework to findOne and updateOne as separate queries.

Upvotes: 2

Related Questions