javascript - Sequelize findOne/findAll 查询不返回关联属性

标签 javascript node.js postgresql sequelize.js

我正在尝试使用 Sequelize 获取基本关联/连接查询,但似乎无法从包含关联中获取返回的数据。到目前为止,我尝试了多种方法都无济于事,但目前正在使用以下方法(为演示而简化):

// package.json
{
  ...
  "dependencies": {
    "pg": "^7.18.1",
    "pg-hstore": "^2.3.3",
    "sequelize": "^5.21.4"
  }
}

// sequelize.js

const Sequelize = require('sequelize')

const options = {
    ...
    databaseVersion: '8.0.2', // RedShift Postgres version
    dialect: 'postgres',
    dialectOptions: {
        ssl: {
            require: true,
            rejectUnauthorized: true
        }
    }
    define: {
        timestamps: false,
        freezeTableName: true
    }
}

const sequelize = new Sequelize(<database>, <user>, <pass>, options)

module.exports = sequelize


// modelA.model.js

const { DataTypes } = require('sequelize')
const sequelize = require('./sequelize')

const schema = 'my_schema'
const tableName = 'my_table_a'
const modelName = 'ModelA'

const attributes = {
    model_a_key: {
        type: DataTypes.CHAR(32)
    },
    model_a_value: {
        type: DataTypes.STRING
    }
    model_b_key: {
        type: DataTypes.CHAR(32)
    },
}

const options = {
    schema
    tableName
}

sequelize.define(modelName, attributes, options)


// modelB.model.js

const { DataTypes } = require('sequelize')
const sequelize = require('./sequelize')

const schema = 'my_schema'
const tableName = 'my_table_b'
const modelName = 'ModelB'

const attributes = {
    model_b_key: {
        type: DataTypes.CHAR(32)
    },
    model_b_value: {
        type: DataTypes.STRING
    }
}

const options = {
    schema
    tableName
}

sequelize.define(modelName, attributes, options)


// associations.js

const { models } = require('./sequelize.js')

ModelA.belongsTo(models.ModelB, { foreignKey: 'model_b_key' })

// Have left this out for now since I can't seem to even leverage the above association properly...
// ModelB.belongsTo(models.ModelA, { foreignKey: 'model_b_key' })


上述文件按 Sequelize 、模型、关联的顺序加载。按照我看到的 Sequelize 示例,我尝试了以下查询来访问 ModelA 及其关联的 ModelB 的数据:

// Attempt #1
await sequelize.models.ModelA.findOne({ include: ['ModelB'] })
// returned data = { model_a_key, model_a_value, model_b_key }; missing all ModelB columns

// Attempt #2
await sequelize.models.ModelA.findOne({ attributes: ['ModelB.model_b_value'], include: ['ModelB'] })
// returned data = {}

// Attempt #3
await sequelize.models.ModelA.findOne({ include: [{ association: 'ModelB', required: true }] })
// returned data = { model_a_key, model_a_value, model_b_key }; missing all ModelB columns

// Attempt #4
await sequelize.models.ModelA.findOne({ include: [{ association: 'ModelB', attributes: ['model_b_value'] }] })
// returned data = { model_a_key, model_a_value, model_b_key }; missing model_b_value


生成的 SQL 似乎在实际获取感兴趣的列方面进行了检查,例如尝试 #1 产生:

SELECT "ModelA"."model_a_key", "ModelA"."model_a_value", "ModelA"."model_b_key", "ModelB"."model_b_key" AS "ModelB.model_b_key", "ModelB"."model_b_value" AS "ModelB.model_b_value"
FROM "my_schema"."my_table_a" AS "ModelA"
LEFT OUTER JOIN "my_schema"."my_table_b" AS "ModelB" ON "ModelA"."model_b_key" = "ModelB"."model_b_key"
LIMIT 1;


如果我设置选项 raw: true ,这些值也可用。但是,如果我尝试使用模型对象,有关关联 ModelB 的所有信息似乎都丢失/丢弃 - 返回的对象上既不存在 ModelB 的嵌套对象,也不存在 ModelB.model_b_keyModelB.model_b_value 的属性。

我在这里错过了一些 super 简单的东西吗?一直在拼命摆弄 targetKeysourceKeyforeignKey 值,以及更多 findOne/findAll 查询排列,如上面列出的那些,但运气为零。

任何建议将不胜感激!

更新我

经过更多的摆弄之后,似乎在设置关联时存在一些区分大小写的奇怪行为。如果我使用别名 as: 'modelb' 定义关联并通过 association: 'modelb' 查询,则上述 fetch 语句将按预期工作并将所需的 ModelB 属性映射到返回的对象上。在别名中引入任何大写字符似乎会破坏此功能 - 例如别名为 xxxxxx 工作正常,xxxxXx 导致上述原始问题。

直接的解决方法似乎是将所有内容都用小写字母作为别名,但我仍然希望按照预期进行工作。我希望这只是与 Postgres 和我的 Sequelize 配置有关,而不是实际问题。

更新 II

因此,似乎所有大写的列引用/别名,虽然在构造的 SQL 查询中表示为定义(例如 SELECT "ModelB"."model_b_key" AS "ModelB.model_b_key" ),但从 pg 客户端返回的行对象属性返回小写(例如 row['modelb.model_b_key'] )。结果,字段标签不再与其原始关联标签对齐,并且没有任何数据映射到模型实例。

设置 Sequelize 选项 minifyAliases: true 似乎可以解决问题。启用此选项后,列别名在查询中表示为 _01_02 等,然后映射回各自的字符串标签,从而避免了别名无意中被转换为小写的可能性。

更新 III

如果有人感兴趣,这实际上似乎是 AWS Redshift 特定的行为。我不知道 Redshift 默认将所有列名(和别名)转换为小写(通过 describe_field_name_in_uppercase 控制),这解释了为什么所有返回的行对象都将其别名转换为小写。我想这对于使用双引号 "" 列名/别名引用来尊重大写/小写的传统 Postgres 实现来说不是问题。

最佳答案

意识到我可以发布答案 - 所以如果其他人遇到这个问题,这些是我目前的发现/解决方案:

So it seems all uppercase column references/aliases, although represented as defined (e.g. SELECT "ModelB"."model_b_key" AS "ModelB.model_b_key") in the constructed SQL query, the returned row object properties from the pg Client are coming back lowercase (e.g. row['modelb.model_b_key']). As a result, the field labels no longer align with their original association label, and none of the data is mapped on to the model instance.

Setting the Sequelize option minifyAliases: true seems to do the trick. With this option enabled, column aliases are represented as _0, _1, etc. in the query and then mapped back to their respective string labels, circumventing the possibility of alias names inadvertently being converted to lowercase.

This actually seems to be an AWS Redshift specific behavior in tandem with Sequelize/pg. I was not aware that Redshift converts all column names (and aliases) to lower case by default (controlled via describe_field_name_in_uppercase), which explains why all returned row objects had their aliases converted to lowercase. I imagine this would not be a problem for a traditional Postgres implementation which would respect upper/lower case using double quotes "" column name/alias references.

关于javascript - Sequelize findOne/findAll 查询不返回关联属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60329345/

相关文章:

javascript - 如何在 ngModules 之间共享服务和状态

javascript - 我可以在 Node.js 进程之间有效地传输 Tensorflow.js 张量吗?

node.js - 尝试在一组包上执行 lerna run --parallel

python - 保存模型时出现丢失列错误

php - Laravel Postgre 无效文本表示

javascript - 选择下拉列表不绑定(bind)值

javascript - Bootstrap 3.3 模态,带有 jQ​​uery 加载和返回值

postgresql - Postgres 函数 now() 返回不正确的时区偏移

javascript - .exit().remove() 似乎删除了折线图图例中的文本,但没有删除矩形

javascript - 如何将数据从 Promise 推送到数组