简体   繁体   中英

How to make mongoose's model.findByIdAndUpdate() trigger model.save()?

I have a mongoose model for users in my database. I have an update controller which calls the findByIdAndUpdate method on my model. Now, when I store passwords in my database I'd like to hash them first, so I have:

userSchema.pre("save", async function(next) {
  // if password is modified then hash it
  next();
});

Now when my update controller calls findByIdAndUpdate it seems to me that model.save() does not get called, so the hashing never happens.

Is there a way to overload the original behavior of findByAndUpdate , or what is a neat solution to this problem?

findByIdAndUpdate triggers the findOneAndUpdate() middleware. Pre and post save() hooks are not executed on findOneAndUpdate().

You cannot access the document being updated in pre('findOneAndUpdate') middleware. If you need to access the document that will be updated, you need to execute an explicit query for the document.

Sample schema with findOneAndUpdate middleware:

const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");

const schema = new mongoose.Schema({
  username: {
    type: String,
    required: true,
    unique: true
  },
  email: {
    type: String,
    required: true,
    unique: true
  },
  password: {
    type: String,
    required: true
  }
});

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

schema.pre("findOneAndUpdate", async function() {
  const docToUpdate = await this.model.findOne(this.getQuery());

  // add your hashing logic to here
  let newPassword = await bcrypt.hash(docToUpdate.password, 12);

  this.set({ password: newPassword });
});

module.exports = mongoose.model("User", schema);

Sample route to test:

router.put("/users/:id", async (req, res) => {
  let result = await User.findByIdAndUpdate(req.params.id, {}, { new: true });

  res.send(result);
});

Note that I used {} inside findByIdAndUpdate, because our password will be hashed in findOneAndUpdate middleware.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM