Sequelize `findOne` 工作不如预期

Sequelize `findOne` working was not as expected

我运行遇到了一个问题,一个星期都没能解决...

当我将用户的电子邮件传递给数据库查询时,sequelize 似乎一切正常并执行此查询,它 returns 来自 table 的数据和找到的结果,但是执行 findOne 函数的结果不是模型,为什么会发生这种情况,我该如何解决?

const email = 'email@example.com'
const user = await User.findOne({ where: { email }})

console.log(user.password) // undefined

这是模型、服务和数据库连接

型号

import { DataTypes, Model } from "sequelize"
import { connection } from "./database"

class User extends Model {
  readonly id: number
  readonly email: string
  password: string
  username: string
  readonly createdAt: Date
  readonly updatedAt: Date
}

User.init(
  {
    id: {
      type: DataTypes.INTEGER,
      autoIncrement: true,
      primaryKey: true,
    },
    email: {
      type: DataTypes.STRING,
      unique: true,
    },
    password: {
      type: DataTypes.STRING,
    },
    username: {
      type: DataTypes.STRING,
    },
  },
  {
    sequelize: connection,
    modelName: "users",
    createdAt: "created_at",
    updatedAt: "updated_at",
  }
)

export default User

服务

export async function loginUser(email: string, password: string):  Promise<ServiceResponse<string>> {
  try {
    const user = await User.findOne({ where: { email } })
    if (!user) {
      throw Error("User not found")
    }

    if (!bcrypt.compareSync(password, user.password)) {
      throw Error("User not found or password did not match")
    }

    const { password: _, ...payload } = user.toJSON()
    const token = jwt.sign(payload, environment.jwt)

    return { success: true, content: token }
  } catch (error) {
    return { success: false, error: error.message }
  }
}

数据库连接

import { Sequelize } from "sequelize"
import { environment } from "../environment"

export const connection = new Sequelize(environment.database, {
  dialect: "postgres",
  logging: console.log,
  dialectOptions: {
    ssl: {
      rejectUnauthorized: false,
    },
  },
})

这是日志

Executing (default): SELECT "id", "email", "password", "username", "created_at", "updated_at" FROM "users" AS "users" WHERE "users"."email" = 'email@example.com';
users {
  dataValues: {
    id: 9,
    email: 'email@example.com',
    password: 'b$s0HFL9eBbcp3GcGkB9cDZuSiCjOEgfQB5lZLxhxXraRfvRF6voDfW',
    username: null,
    created_at: 2020-11-16T13:09:30.631Z,
    updated_at: 2020-11-16T13:09:30.631Z
  },
  _previousDataValues: {
    id: 9,
    email: 'email@example.com',
    password: 'b$s0HFL9eBbcp3GcGkB9cDZuSiCjOEgfQB5lZLxhxXraRfvRF6voDfW',
    username: null,
    created_at: 2020-11-16T13:09:30.631Z,
    updated_at: 2020-11-16T13:09:30.631Z
  },
  _changed: Set(0) {},
  _options: {
    isNewRecord: false,
    _schema: null,
    _schemaDelimiter: '',
    raw: true,
    attributes: [
      'id',
      'email',
      'password',
      'username',
      'created_at',
      'updated_at'
    ]
  },
  isNewRecord: false,
  id: undefined,
  email: undefined,
  password: undefined,
  username: undefined,
  createdAt: undefined,
  updatedAt: undefined
}

已用堆栈NextJS, Sequelize, PostgreSQL

我做错了什么?

您检查过您的用户对象是否也未定义?

尝试user.dataValues.password获取密码。 或者你可以像这样添加 raw: true const user = await User.findOne({ raw:true, where: { email }}).Sequelize 将 return 只有数据而不是模型实例。所以你可以使用 user.password

模型实例使用 dataValues 属性 的概念进行操作,它存储实例表示的实际值。 正如您在 dataValues 下的打印输出中看到的那样,您有自己的模型:

Executing (default): SELECT "id", "email", "password", "username", "created_at", "updated_at" FROM "users" AS "users" WHERE "users"."email" = 'email@example.com';
users {
  dataValues: {
    id: 9,
    email: 'email@example.com',
    password: 'b$s0HFL9eBbcp3GcGkB9cDZuSiCjOEgfQB5lZLxhxXraRfvRF6voDfW',
    username: null,
    created_at: 2020-11-16T13:09:30.631Z,
    updated_at: 2020-11-16T13:09:30.631Z
  },
  _previousDataValues: {
      (...)

要从此 dataValues 字段获取数据,您可以使用 get 方法。 还有findOnereturn一个承诺。

综合考虑,在你的情况下我认为这应该可行

const email = 'email@example.com'
User.findOne({ where: { email }}).then(data => {
    console.log(data.get('password')
});

看看Sequelize Model documentation

谢谢,答案是 Model.get({ plain: true }) 在处理接收到的数据之前。