【问题标题】:Sequelize class method works fine but instance method is not workingSequelize 类方法工作正常,但实例方法不起作用
【发布时间】:2022-01-24 06:24:28
【问题描述】:

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

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

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 返回常规对象(来自 lodash.pick)。但是您正在 Sequelize 实例上定义您的实例方法。
  • 感谢您的评论艾玛。您能否提示我如何返回 Sequelize 实例而不是从 findByEmailAndPassword 返回常规对象?我在这里要做的是避免在我的响应正文中发送用户密码。是否有可能以另一种方式做到这一点而不会出现这种问题?

标签: node.js express sequelize.js


【解决方案1】:

首先,您遇到问题的原因是 findByEmailAndPassword_.pick 返回常规对象,并且您正在为 Sequelize 实例定义实例方法。此实例方法可以在 Sequelize 实例上调用,而不是在常规对象上。

但是,你的目标是

我在这里尝试做的是避免在我的响应正文中发送用户密码。

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

您可以将您的用户模型定义为

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

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

范围适用于 .find、.findAll、.count、.update、.increment 和 .destroy。

我还测试了它也适用于.findByPk.findOne

那么,如何使用...

调用常规的 Sequelize findOne 函数。

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

默认情况下,由于应用了defaultScope,因此不会返回password 作为响应。

在某些需要返回password的场景下,使用unscoped禁用defaultScope

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

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

【讨论】:

  • 非常感谢艾玛 :)
猜你喜欢
  • 2016-09-04
  • 1970-01-01
  • 2019-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-14
相关资源
最近更新 更多