Sequelize class 方法工作正常但实例方法不起作用

Sequelize class method works fine but instance method is not working

我已经在Sequelize中定义了一个用户模型,还为它定义了一个自定义的class方法和一个实例方法。我在登录 api 中调用了这两种方法(效果很好)。问题是 class 方法完美运行,但实例方法导致错误,我无法识别我的代码有什么问题。请帮忙。

这是我的用户模型及其方法:

const Sequelize = require("sequelize");
const sequelize = require("../db/db.config");
const bcrypt = require("bcryptjs");
const _ = require("lodash");
const jwt = require("jsonwebtoken");

const User = sequelize.define("user", {
  id: {
    type: Sequelize.INTEGER,
    autoIncrement: true,
    allowNull: false,
    primaryKey: true,
  },
  first_name: {
    type: Sequelize.STRING(50),
    allowNull: false,
  },
  last_name: {
    type: Sequelize.STRING(50),
    allowNull: false,
  },
  email: {
    type: Sequelize.STRING(50),
    allowNull: false,
    validate: {
      isEmail: true,
    },
  },
  password: {
    type: Sequelize.STRING(100),
    allowNull: false,
  },
});

User.prototype.testMethod = function () {
  console.log("THIS IS A TEST");
};

User.beforeCreate(async (user, options) => {
  const hashedPassword = await bcrypt.hash(user.password, 10);
  user.password = hashedPassword;
});

User.findByEmailAndPassword = async function (inputEmail, inputPassword) {
  try {
    const user = await User.findOne({ where: { email: inputEmail } });

    if (user === null) {
      return null;
    }

    const passwordMatch = await bcrypt.compare(inputPassword, user.password);
    if (!passwordMatch) {
      return null;
    }

    return _.pick(user, "id", "first_name", "last_name", "email");
  } catch (error) {
    console.log("FIND BY EMAIL AND PASSWORD ERROR: ", error);
  }
};

module.exports = User;

这是我的登录路由器:

const express = require("express");
const router = express.Router();
const User = require("../models/user.model");

router.post("/api/login", async (req, res) => {
  try {
    const user = await User.findByEmailAndPassword(
      req.body.email,
      req.body.password
    );
    console.log("USER: ", user);

    await user.testMethod();

    if (!user) {
      return res.status(400).send({
        errorMessage: "Username and password combination is not correct!",
      });
    }

    return res.status(200).send(user);
  } catch (error) {
    res.status(400).send({ errorMessage: error });
  }
});
module.exports = router;

谢谢。

首先,您遇到问题的原因是 findByEmailAndPassword 是 return 从 _.pick 中获取常规对象,并且您正在为 Sequelize 定义实例方法实例。此实例方法可以在 Sequelize 实例而不是常规对象上调用。

但是,你的目标是

What I'm trying to do here is to avoid sending user password in my response body.

defaultScope 非常适合这个用例。它允许您在模型上定义一些重复的选项。

您可以将用户模型定义为

const User = sequelize.define("user", {
  id: {
    type: Sequelize.INTEGER,
    autoIncrement: true,
    allowNull: false,
    primaryKey: true,
  },
  ...
}, {
  defaultScope: {
    attributes: {
      exclude: ['password']
    }
  }
});

在模型上定义 defaultScope,这将默认应用于许多 Sequelize 函数。

Scopes apply to .find, .findAll, .count, .update, .increment and .destroy.

我也测试过它也适用于.findByPk,.findOne.

那么,如何使用...

调用常规 Sequelize findOne 函数。

const user = User.findOne({ 
  where: {
    email: req.body.email,
    password: req.body.password
  }
}); 

默认情况下,由于应用了 defaultScope,因此不会 return password 响应。

在某些需要return password 的情况下,使用unscoped 禁用defaultScope

// This will return `password` in response.
User.unscoped().fineOne(...)

供参考:https://sequelize.org/master/manual/scopes.html