Virtual field not setting field in mongoose model

假装没事ソ 提交于 2019-12-13 04:06:24

问题


I am new to nodeJS and mongoose. I am trying to make a user model that does not save a password as plain text. In other backend frameworks you can accomplish this with an ORM by utilizing a virtual field. I looked up the docs for Mongoose and found that this can be accomplished. Following the dics I created the following Mongoose model. Mind you this is not the final implementation and is for merely testing my understanding of how Mongoose handle virtual fields.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const userSchema = new Schema({
  name: {type: String, required: true},
  email: {type: String, required: true},
  passwordHash: {type: String, required: true}
});

userSchema.virtual("password")
  .get(() => this._password)
  .set(val => {
    this._password = val;
    console.log("setting: ", val);
    this.passwordHash = "test";
  })


module.exports = mongoose.model("Users", userSchema);

I also have the following test for this model

it("should not save passwords as plain test", done => {
    const user = new User({name: "john", email: "john@example.com",     password: "password1234"});
    console.log(user);
    user.validate(({errors}) => {
      expect(errors).to.not.exist
    });
    done();
  }); 

The test fails because I have an error. The error states that the passwordHash field is missing. I know I have that field as required, but I assign the value "test" to this.passwordHash in the set function just like the docs say to do. This is where I get stuck. Any guidance is much appreciated.


回答1:


I think problem is with this context in userSchema.virtual("password") function

userSchema.virtual("password")
  .get(() => this._password) // this points to global object
  .set(val => {
    this._password = val; // this points to global object
    console.log("setting: ", val);
    this.passwordHash = "test";
  });

This is one of exceptions when you cant use Arrow function.

userSchema.virtual("password")
  .get(function() {
      return this._password;
  })
  .set(function(val) {
    this._password = val;
    console.log("setting: ", val);
    this.passwordHash = "test";
  });

Let me know is it working now properly.

My general advice: for hash/check passwords use Schema.pre('save') hook. Eg.:

// before save user
userSchema.pre('save', function(next) {
  if (this.isModified('password')) { //only if password is modified then hash
    return bcrypt.hash(this.password, 8, (err, hash) => {
      if (err) {
        return next(err);
      }
      this.password = hash; //save hash in UserSchema.password in database
      next();
    });
  }
  next();
});

Schema.pre is part of middleware. More about middleware in mongoose: http://mongoosejs.com/docs/middleware.html



来源:https://stackoverflow.com/questions/49440561/virtual-field-not-setting-field-in-mongoose-model

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!