猫鼬模式实例方法不是函数

Mongoose Schema Instance Methods is Not a Function

我以前有一个工作版本的 mongoose 实例方法。我不确定这次有什么不同。这次我唯一不同的是,我将 server.js 文件之外的 mongoose 连接函数分离到一个配置文件中,该配置文件将被导入并调用 connect() 函数。

我将主要使用护照中的这个实例方法和本地策略来登录用户。当我去调用之前 UserModel.findOne({ email }) 找到的用户实例上的实例方法时,verify(password) 实例方法没有被调用,也没有抛出任何错误。

出于测试目的,我尝试将 UserModel.findOne() 硬编码到连接字段中,我确实让用户回来了。然后我决定立即从返回的名为 verify().

的用户实例调用我的实例方法

我还尝试将方法的名称更改为 comparePassword,我尝试使用静态方法进行测试以检查它是否被调用(实际上没有),我还试图研究其他方法来导入我的模式和模型,但这似乎不起作用。我已经尝试过 Async/Await 没有改变输出


文件:mongo.db.js

const connect = () => {
  return new Promise((resolve, reject) => {
    mongoose.connect(
      config.get('DB.STRING'),
      { useCreateIndex: true, useNewUrlParser: true },
      async (err) => {
        if (err) reject(err)
        resolve()
        // TESTING INSTANCE METHODS
        await mongoose.connection
          .collection('users')
          // HARD CODED TEST EMAIL
          .findOne({ email: 'braden_feeney@hotmail.com' }, (err, result) => {
            if (err) reject(err)
            console.log(result)
            console.log(result.verify('test1234'))
          })
      },
    )
  })
}

const close = () => {
  return mongoose.disconnect()
}

export default { connect, close }

文件:passport.config.js

passport.use(
  new LocalStrategy(
    {
      usernameField: 'email',
      passwordField: 'password',
    },
    async (email, password, done) => {
      try {
        // Find the user given the email
        const user = await User.findOne({ email })
        // If not found
        if (!user) return done(null, false)
        // Check if the password is correct
        const isValididated = await user.verify(password)
        // If not matched
        if (!isValididated) return done(null, false)

        // Return the user
        done(null, user)
      } catch (error) {
        done(error, false)
      }
    },
  ),
)

文件:users.model.js

const UserSchema = new Schema(
  // HIDDEN FOR SECURITY
  { ... },
  { versionKey: false, timestamps: true },
)

// HIDDEN FOR SECURITY - PRE SAVE WORKS AS EXPECTED
UserSchema.pre('save', async function(next) { ... })

// THIS IS THE METHOD THAT SHOWS AS 'Not a Function'
UserSchema.methods.verify = function(password) {
  bcrypt.compare(password, this.password, (err, res) => {
    if (err) return new Error(err)
    return res
  })
}

export default model('User', UserSchema)

当我调用 user.verify(password) 时,我希望看到函数返回一个布尔值。

实际结果是抛出错误说明 TypeError: user.verify is not a function

这一段没有意义:

async (email, password, done) => {
    try {
        const user = await User.findOne({ email })
        if (user) // <-- if you have a user record
          return done(null, false) // <-- you return!
        // There was no valid user ... how would there be user.verify?
        const isValididated = await user.verify(password)
        if (!isValididated) return done(null, false)
          done(null, user)
    } catch (error) {
        done(error, false)
    }
}

您似乎 return 有效用户,但在您没有用户时调用 user.verify。看来你的流程有点问题。

在研究了 mongoose 如何创建实例方法之后,我尝试使用另一种方法来使该方法起作用。我不得不将 bcrypt.compare() 包装在一个承诺中,因为我的代码没有等待响应。

文件:users.model.js

UserSchema.method('verify', function(password) {
  return new Promise((resolve, reject) => {
    bcrypt.compare(password, this.password, (err, res) => {
      if (err) reject(err)
      resolve(res)
    })
  })
})

我仍然更喜欢我的问题中提到的方式,因为我认为它看起来更干净并且不依赖字符串作为方法名称。

你所要做的就是用“async”标记这个函数。

// THIS IS THE METHOD THAT SHOWS AS 'Not a Function'
UserSchema.methods.verify = async function (password) {
  bcrypt.compare(password, this.password, (err, res) => {
    if (err) return new Error(err)
    return res
  })
}

& 另一件你要记住的事情是,当你从你的数据库中检索用户时,确保在那里也使用“await”关键字。 我遇到了同样的错误然后我注意到我忘记使用“await”关键字并且我的代码甚至没有等待“用户”从数据库到达并且我们没有用户或实例就进入了下一行并且我们在尚未从数据库到达的实例上调用“比较”方法。

这就是为什么您收到 comparePassword 不是函数的错误。