imharjyotbagga
imharjyotbagga

Reputation: 329

Mongoose middleware schema.pre('save', ...)

I am making a REST API in NodeJS using the Mongoose Driver. I want to hash the passwords before saving them. For the same, I am using Mongoose Schema, where I made a userSchema for my user model. And for hashing I used the following function.

userSchema.pre('save', async (next) => {
    const user = this;
    console.log(user);
    console.log(user.isModified);
    console.log(user.isModified());
    console.log(user.isModified('password'));
    if (!user.isModified('password')) return next();
    console.log('just before saving...');
    user.password = await bcrypt.hash(user.password, 8);
    console.log('just before saving...');
    next();
});

But on creating a user or modifying it I am getting Error 500, and {} is getting returned. My routers are as follows.

router.post('/users', async (req, res) => {
    const user = User(req.body);
    try {
        await user.save();
        res.status(201).send(user);
    } catch (e) {
        res.status(400).send(e);
    }
});

router.patch('/users/:id', async (req, res) => {
    const updateProperties = Object.keys(req.body);
    const allowedUpdateProperties = [
        'name', 'age', 'email', 'password'
    ]; 
    const isValid = updateProperties.every((property) => allowedUpdateProperties.includes(property));
    if (!isValid) {
        return res.status(400).send({error: "Invalid properties to update."})
    }

    const _id = req.params.id;
    try { 
        const user = await User.findById(req.params.id);
        updateProperties.forEach((property) => user[property] = req.body[property]);
        await user.save();
        if (!user) {
            return res.status(404).send();
        }
        res.status(200).send(user);
    } catch (e) {
        res.status(400).send(e);
    }
});

And the following is my console output.

Server running on port 3000
{}
undefined

On commenting out the userSchema.pre('save', ...) everything is working as expected. Please can you help me figure out where am I going wrong.

Upvotes: 4

Views: 18453

Answers (3)

Darshan Domadiya
Darshan Domadiya

Reputation: 1

userSchema.pre("save", async function(next){
    if(!this.isModified("password")) return next();
    this.password = await bcrypt.hash(this.password,10);
})

Upvotes: 0

Shiplu
Shiplu

Reputation: 516

The factor is the function, with the function keyword here. In simple words, inside the function, this can be a reference to the entire page you are coding for. Try out the code.

 userSchema.pre("save", async function(next) {
  if (!this.isModified("password")) {
    return next();
  }
  const salt = await bcrypt.genSalt(10);
  const hashedPassword = await bcrypt.hash(this.password, salt);
  this.password = hashedPassword;
  next();
});

Upvotes: 0

hoangdv
hoangdv

Reputation: 16157

Using function definition instead of arrow function for mongoose pre save middleware:

userSchema.pre('save', async function(next) { // this line
    const user = this;
    console.log(user);
    console.log(user.isModified);
    console.log(user.isModified());
    console.log(user.isModified('password'));
    if (!user.isModified('password')) return next();
    console.log('just before saving...');
    user.password = await bcrypt.hash(user.password, 8);
    console.log('just before saving...');
    next();
});

Update:

The difference is this context, if you use arrow function in this line const user = this;, this now is your current file (schema file, I guess).

When you use function keyword, this context will belong to the caller object (user instance).

Upvotes: 15

Related Questions