jmona789
jmona789

Reputation: 2839

user.isModified is not a function when doing a pre update in mongoose

I'm trying to hash passwords in an app I'm building and they are hashing fine when I create a user by calling this function(coffeesctipt):

UserSchema.pre 'save', (next) ->
  user = this
  hashPass(user, next)

hashPass = (user, next) ->
  # only hash the password if it has been modified (or is new)
  if !user.isModified('password')
    return next()
  # generate a salt
  bcrypt.genSalt SALT_WORK_FACTOR, (err, salt) ->
    if err
      return next(err)
    # hash the password using our new salt
    bcrypt.hash user.password, salt, (err, hash) ->
      if err
        return next(err)
      # override the cleartext password with the hashed one
      user.password = hash
      next()
      return
    return

but when I do an update and have this pre:

UserSchema.pre 'findOneAndUpdate', (next) ->
  user = this
  hashPass(user, next)

I get TypeError: user.isModified is not a function if I console log user in the pres the save pre logs the user I am updating, the findandupdate pre does not,id there to way to access the document in the pre or do I need to do this another way?

NOTE: The above functions are NOT arrow functions. They are normal functions written in CoffeeScript with ->, they compile into js with normal functions.

Upvotes: 12

Views: 13688

Answers (6)

Shubhradeep Maity
Shubhradeep Maity

Reputation: 1

Instead of using arrow function use normal function like async function(next){}

Upvotes: 0

Nahid Estes
Nahid Estes

Reputation: 19

Don't use the arrow operator for the callback, that'll change the scope this. Define a regular function; it may help you to solve this problem.

Upvotes: 1

hiep ninh
hiep ninh

Reputation: 65

Be careful when using middleware in mongoose, in that case of "save" or "updateOne", this refers to a query, not a document. It should look like this

schema.pre(type, { document: true, query: false }, async function (next) 
{
     if(this.isModified('password')) {
            //Do the hash
     }
     next();
});

Upvotes: 3

TanDev
TanDev

Reputation: 437

I know this might be way too late for you, but for any future coders that land on this issue, I think this solution should work. So, since save() is a middleware inside .pre, that overrides some of mongoose's methods, such as findByIDAndUpdate. What you might want to do is instead of using that, break your code up like this if you have patch request firing off somewhere:

const user = await User.findById(req.params.id);
    updates.forEach((update) => {
      user[update] = req.body[update];
    });

Upvotes: 0

Eric Lloyd
Eric Lloyd

Reputation: 467

You get an error because the arrow function changes the scope of 'this.' Just use

UserSchema.pre('save', function(next){})

Upvotes: 28

orlaqp
orlaqp

Reputation: 622

I had a similar issue on typescript and it turns out that is was related to the arrow operator you are also using. Not sure how to change this in coffescript right now but I think that should fix your issue.

you have to change this line:

hashPass = (user, next) ->

Check this out: https://github.com/Automattic/mongoose/issues/4537

Upvotes: 1

Related Questions