Search code examples
node.jsmongoosepassword-encryption

Mongoose schema wouldn't call middleware to hash password


My Mongoose schema looks like this:

import mongoose from 'mongoose';
import argon2 from 'argon2';
import argonConfigs from '../configs/argon-configs';

const { Schema } = mongoose;
const userSchema = new Schema({
  firstName: String,
  lastName: String,
  googleID: String,
  twitterID: String,
  emails: [String],
  hasPicture: Boolean,
  signupToken: String,
  token: String,
  username: String,
  password: String,
});

userSchema.pre('save', async function(next) {
  console.log('inside pre');
  if (this.password) {
    console.log('this.password', this.password);
    this.password = await argon2.hash(password, argonConfigs);
  }
  next();
});

const User = mongoose.model('user', userSchema);

module.exports = User;

I amusing this schema to update records in my collection like this:

import User from '../models/user';

export const tokenInDB = async (token, email) => {
  const existingUser = await User.findOne({ token: token, emails: email, password : { $exists : false } });
  return existingUser;
};

export const createAccount = async (fname, lname, uname, pass, existingUser) => {
  let fieldsToUpdate = {};
  if(fname) { fieldsToUpdate.firstName = fname }
  if(lname) { fieldsToUpdate.lastName = lname }
  if(uname) { fieldsToUpdate.username = uname }
  if(pass) { fieldsToUpdate.password = pass }
  const updatedUser = await User.findOneAndUpdate({_id: existingUser._id}, {...fieldsToUpdate, $unset: {token: 1}}, {new: true});
  return updatedUser;
};

I'm expecting the middleware (userSchema.pre()) to kick in every time the update is made. This middleware should then use the argon2i library to hash the plaintext password entered by the user.

However, the middleware refuses to get called. The console.log() inside the function remains uncalled. How do I fix this?


Solution

  • In your createAccount function, you used findOneAndUpdate() and this function just trigger findOneAndUpdate middleware, not save middleware so the console.log not reached.

    You can solve your problem by:

    • Option 1: use findOne() or findById() to find the user, change its fields and then call save(). It will trigger your save middleware.

    • Option 2: register the findOneAndUpdate middleware and hash your password in it but note that, findOneAndUpdate is query middleware so thís will refer to the query, not to the document like in save middleware.