Mongoose Schema.method() не работает и показывает сообщение об ошибке

#node.js #mongodb #mongoose #mongoose-schema

#node.js #mongodb #mongoose #mongoose-schema

Вопрос:

Я принимаю ввод пароля от пользователя и шифрую пароль с помощью криптографии, а затем сохраняю в базе данных. Это мой код, здесь я сохраняю зашифрованный пароль в свойстве encry_password, которое поступает из пользовательской схемы. Но это выдает мне сообщение о том, что «this.securePassword» не является функцией.

 const mongoose = require("mongoose");
const crypto = require("crypto");
const { v1: uuidv1 } = require("uuid");

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    maxlength: 32,
    trim: true,
  },
  lastname: {
    type: String,
    maxlength: 32,
    trim: true,
  },
  email: {
    type: String,
    trim: true,
    required: true,
    unique: true,
  },
  usrinfo: {
    type: String,
    trim: true,
  },
  encry_password: {
    type: String,
    required: true
  },
  salt: String,
  role: {
    type: Number,
    default: 0,
  },
  purchases: {
    type: Array,
    default: [],
  },
}, { timestamps: true });


userSchema.virtual("password")
  .set((password) => {
    this._password = password;
    this.salt = uuidv1();
    this.encry_password = securePassword(password, uuidv1());
    console.log(this.encry_password);
  })
  .get(() => {
    return this._password;
  });

// const authenticate = function (plainPassword, encry_password) {
//   return securePassword(plainPassword) === encry_password;
//   };

const securePassword = function (plainPassword, salt) {
  if (!plainPassword) return "";
  try {
    return crypto.createHmac("sha256", salt).update(plainPassword).digest("hex");
  } catch (error) {
    return "";
  }
};


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

 

Маршрут для регистрации пользователя

 exports.signup = (req, res) => {
    console.log(req.body);
    const user = new User(req.body);
    user.save((err, user) => {
        if (err) {
            console.log(err);
            res.status(400).json({
                err: "Note able to save the user in database"
            });
        } else {
            res.json(user);
        }
    });
};

 

Ответ №1:

прежде всего, в этой ситуации вы не должны использовать virtual

Виртуалы

Виртуальные объекты — это свойства документа, которые вы можете получить и установить, но которые не сохраняются в MongoDB. Геттеры полезны для форматирования или объединения полей, в то время как сеттеры полезны для разбиения одного значения на несколько значений для хранения.

но в области virtual , this не удается получить доступ к методу, вы не можете получить доступ к методу, как ваш способ, это пример использования метода в mongoose

   const Animal = mongoose.model('Animal', animalSchema);
  const dog = new Animal({ type: 'dog' });

  dog.findSimilarTypes((err, dogs) => {
    console.log(dogs); // woof
  });
 

вы можете проверить документирование метода:

если вы хотите просто получить доступ к securePassword своему способу, вам может понравиться это и удалить метод mongoose complately, потому что это не то место, которое нужно использовать method :

 UserSchema.virtual("password")
  .set((password) => {
    this._password = password;
    this.salt = uuidv1();
    console.log("This is running");
    this.encry_password = securePassword(password, this.salt);
    console.log(encry_password);
  })
  .get(() => {
    return this._password;
  });

const authenticate = function (plainPassword, encry_password) {
  return securePassword(plainPassword) === encry_password;
};

const securePassword = function (plainPassword, salt) {
  if (!plainPassword) return "";
  try {
    return crypto
      .createHmac("sha256", salt)
      .update(plainPassword)
      .digest("hex");
  } catch (error) {
    return "";
  }
};
 

если вы хотите создать authenticate service , измените свой способ и не используйте virtual для пароля и использования pre save

перед сохранением информации о пользователях в БД эта задача будет выполнена ознакомьтесь с предварительной документацией

 userSchema.pre("save", async function (next) {
  try {
    this.password = securePassword (plainPassword, salt);
  } catch (error) {
    console.log(error);
  }
});
 

после создания хэш-пароля сохраните информацию следующим образом :

 const userSchema = new mongoose.Schema({
    .
    .
    .
    password: { //convert encry_password to password
      type: String,
    }
    .
    .
    .
  }, { timestamps: true });
  //every time want to user save this method called
  userSchema.pre('save', function (next) {
    this.salt = uuidv1()
    this.password = securePassword(this.password, this.salt)
    next()
 })
 //for have a clean  routes, you can create a static methods
 userSchema.statics.Create = async (data) => {
    let model = new User(data); 
    let resUser = await model.save(); //save your user
    return resUser;
  };

  const securePassword = function (plainPassword, salt) {
    if (!plainPassword) return "";
    try {
      return crypto.createHmac("sha256", salt).update(plainPassword).digest("hex");
    } catch (error) {
      return "";
    }
  };
  
  let User  = mongoose.model("User", userSchema)
  module.exports = {User};
 

измените контроллер следующим образом :

 let {User} = require("./path of user schema")
exports.signup = async (req, res) => {
  try {
    console.log(req.body);
    const user = await User.create(req.body); //create a user
    res.json(user);
  } catch (error) {
    console.log(err);
    res.status(400).json({
      err: "Note able to save the user in database",
    });
  }
};
 

ПРИМЕЧАНИЕ: в req.body поле имени пароля должно быть password

Комментарии:

1. Я запускаю этот код, он работает нормально, и я могу сохранить зашифрованный пароль в этом свойстве.encry_password. Но проблема в том, что перед сохранением пароля в этом свойстве.encry_password в базе данных сохраняется нулевая информация, поэтому она выдает ошибку «требуется this.encry_password».

2. пожалуйста, полностью добавьте ваш файл схемы в вопрос

3. вы должны изменить свой способ и не использовать virtual, в virtual области видимости невозможно получить доступ к полям схемы с this помощью, используйте pre save ,

4. Я добавил весь свой файл схемы, теперь вы можете проверить

5. вы хотите создать пользователя с хэш-паролем? это правильно?

Ответ №2:

Похоже, что область действия функции securePassword определена внутри UserSchema, и вы пытаетесь вызвать ее в UserSchema.virtual.

Комментарии:

1. Можете ли вы помочь мне решить эту проблему?