【问题标题】:Why do I get an error when I try to save mongoose model?为什么我尝试保存 mongoose 模型时会出错?
【发布时间】:2021-12-13 13:57:26
【问题描述】:

我正在尝试在 Node.JS 中创建用于重置用户密码的控制器。 这个想法是根据重置密码令牌从数据库中获取用户,进行一些验证更新相关字段并将其保存回数据库。 但是,尝试保存更新的用户时出现错误(“user.save 不是函数”)。 可能是什么原因?

我有一个用户模型定义如下:

const mongoose = require("mongoose");
const validator = require("validator");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const crypto = require("crypto");

const userSchema = new mongoose.Schema({
  name: {
    type: String,
    required: [true, "Please enter valid name"],
    maxLength: [30, "Your name cannot exceed 30 characters]"],
  },
  email: {
    type: String,
    required: [true, "Please enter valid email"],
    unique: true,
    validate: [validator.isEmail, "Please enter valid email address"],
  },
  password: {
    type: String,
    requires: [true, "Please enter your password"],
    minLength: [6, "Your password must be at least 6 characters"],
    select: false,
  },
  avatar: {
    public_id: { type: String, required: true },
    url: { type: String, required: true },
  },
  role: { type: String, default: "user" },
  createdAt: { type: Date, default: new Date().now },
  resetPasswordToken: { type: String },
  resetPasswordExpire: { type: Date },
});

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

// check password matching
userSchema.methods.isPasswordMatched = async function (inputPassword) {
  return await bcrypt.compare(inputPassword, this.password);
};

// return JSON Web Token
userSchema.methods.getJwtToken = function () {
  return jwt.sign({ id: this.id }, process.env.JWT_SECRET, {
    expiresIn: process.env.JWT_EXPIRESIN_TIME,
  });
};

// Generate password token
userSchema.methods.getResetPasswordToken = function () {
  // Generate Token
  const resetToken = crypto.randomBytes(20).toString("hex");

  // Hash token
  this.resetPasswordToken = crypto
    .createHash("sha256")
    .update(resetToken)
    .digest("hex");

  // set expired time
  this.resetPasswordExpire = new Date(Date.now() + 30 * 60 * 1000);

  return resetToken;
};

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

当我尝试重置用户密码时,我会尝试以下操作:

  // get the user document from db (make sure token and expiration time are valid)
let user = User.findOne({
    resetPasswordToken: resetPasswordToken,
    resetPasswordExpire: { $gt: Date.now() },
  });

// update password
  user.password = req.body.password;
  user.resetPasswordToken = undefined;
  user.resetPasswordExpire = undefined;
  user.save();
  sendToken(user, 200, res);

由于某种原因,我收到一个错误: "errorMsg": "user.save 不是函数"

可能是什么问题?

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

    可能用户为空或未定义,因此您应该处理用户空条件。 还有findOne和save返回promise,所以需要在它们前面加上await关键字。

    另外,您在用户架构密码字段中有错字,requires 应该是 required

    let user = await User.findOne({
      resetPasswordToken: resetPasswordToken,
      resetPasswordExpire: { $gt: Date.now() },
    });
    
    if (user) {
      // update password
      user.password = req.body.password;
      user.resetPasswordToken = undefined;
      user.resetPasswordExpire = undefined;
      await user.save();
      sendToken(user, 200, res);
    } else {
      res.status(400).send("No user found");
    }
    

    如果你让用户为空,你需要在 findOne 中修复你的查询。

    【讨论】:

    • 谢谢。我的用户查询返回正确的文档并添加 await 不会改变结果(尽管您显然对它丢失是正确的:-))还有其他想法吗?
    • 如果你在这个答案中使用我的代码会发生什么?
    • 另外您在用户架构密码字段中有错字,requires 应该是 required
    • 修复错字修复了问题 :-) 不确定错误消息的相关性...无论如何,非常感谢!
    【解决方案2】:

    使用 await 关键字让猫鼬水合响应

    let user = await User.findOne({
            resetPasswordToken: resetPasswordToken,
            resetPasswordExpire: { $gt: Date.now() },
          });
        
        // update password
          user.password = req.body.password;
          user.resetPasswordToken = undefined;
          user.resetPasswordExpire = undefined;
          user.save();
          sendToken(user, 200, res);
    

    或者你可以这样做

    await User.findOneAndUpdate({
            resetPasswordToken: resetPasswordToken,
            resetPasswordExpire: { $gt: Date.now() },
          },{password : req.body.password, resetPasswordToken : undefined, 
          resetPasswordExpire : undefined,});
    

    【讨论】:

    • 感谢您的快速回复。我最初使用等待。它不会改变结果。使用“findOneAndUpdate”时,我收到类似的错误。在这种情况下,它说“user.getJwtToken 不是函数”,这当然是 Schema.methods 中定义的函数。
    猜你喜欢
    • 1970-01-01
    • 2014-11-18
    • 1970-01-01
    • 2019-12-03
    • 1970-01-01
    • 2018-12-12
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    相关资源
    最近更新 更多