Modermo
Modermo

Reputation: 1992

Async function in mongoose pre save hook not working

Calling an async function in a pre save hook is returning me undefined for the password. Am I fundamentally misunderstanding async here? I've used it successfully in other areas of my app an it seems to be working fine...

userSchema.pre('save', function (next) {

  let user = this

  const saltRounds = 10;

  const password = hashPassword(user)
  user.password = password;

  next();

})


async hashPassword(user) {

    let newHash = await bcrypt.hash(password, saltRounds, function(err, hash) {

    if (err) {
      console.log(err)
    }

    return hash    

  });

  return newHash

}

Upvotes: 4

Views: 6775

Answers (3)

vijayant
vijayant

Reputation: 168

Mongoose hooks allow async functions in them. It worked for me. Note that the "next" callback parameter is not needed in async functions as the function executes synchronously.

Here is what a correct async/await version of the code posted in the question would be. Please note that the corrections are marked in bold:

userSchema.pre('save', async function () {
  
  let user = this;

  const saltRounds = 10;

  const hashed_password = await hashPassword(user.password, saltRounds);

  user.password = hashed_password;

}); // pre save hook ends here

async hashPassword(password, saltRounds) {

  try {

    let newHash = await bcrypt.hash(password, saltRounds);

  } catch(err){

    // error handling here

  }

  return newHash;

}

Upvotes: 3

sansSpoon
sansSpoon

Reputation: 2185

Just to clean things up a bit:

userSchema.pre('save', function(next) {
    if (!this.isModified('password')) {
        return next();
    }

    this.hashPassword(this.password)
        .then((password) => {
            this.password = password;
            next();
        });
});

userSchema.methods = {
    hashPassword(password) {
        return bcrypt.hash(password, 10);
    },
}
  • let user = this can be dropped when using an arrow function in then.
  • When using bcrypt.hash() with no callback, it returns a promise.
  • async for hashPassword is redundant when using .then when calling

Upvotes: 0

Robert Moskal
Robert Moskal

Reputation: 22553

I think you'd need to handle the promise returned by hashPassword:

 hashPassword(user)
 .then(password => {user.password = password
                    next()}
 )

I don't think you can turn userSchema.pre into an async function.

Upvotes: 4

Related Questions