【问题标题】:Sequelize.js: join tables without associationsSequelize.js:连接没有关联的表
【发布时间】:2020-07-17 17:48:23
【问题描述】:

有没有办法在 sequelize 中加入没有使用 include 定义的关联的表?这不是 this 的副本。我说的是完全没有关联但有我想加入的列的表。

例子:

select * from bank
left outer join account 
    on account.bank_name = bank.name

上述查询将返回表bank 中的所有记录,而不管指定约束适用的account 记录是否存在。

如果模型bankaccountaccount.bank_name = bank.name 相关联,则在续集中,这将如下所示:

bank.findAll({
    include: [{
        model: account,
        required: false,
    }]
})

但是,如果模型没有关联怎么办?有没有办法编写我自己的自定义 on 部分或等效部分:

bank.findAll({
    include: [{
        model: account,
        required: false,
        on: {
            bank_name: Sequelize.col('bank.name')
        }
    }]
})

我隐约记得读过一些关于此的内容,但我现在似乎无法在任何地方找到该文档。如果您能指出文档中的正确部分,我们将不胜感激。

【问题讨论】:

  • 嗨,找到答案的任何成功。其实我也面临着类似的情况。
  • 相同。我似乎无法理解这样的事情可能会丢失的事实

标签: join sequelize.js


【解决方案1】:

似乎虽然可以定义自定义on 条件,但如果不先定义associations,就不可能定义include 关系。 findAll 方法的文档措辞暗示了这一点(在页面上搜索 options.include):

使用左连接急切加载的关联列表。支持的是 { include: [ Model1, Model2, ...]} 或 { include: [{ model: Model1, as: 'Alias' }]} 或 { include: ['Alias']}。如果您的关联是用 as 设置的(例如 X.hasMany(Y, { as: 'Z },您需要在预加载 Y 时在 as 属性中指定 Z)。

options.include[].on 上的文档更加简洁:

为加入提供您自己的 ON 条件。

我最终使用 Postgres 视图作为解决方法解决了我的问题。也可以注入raw query 并绕过续集限制,但我只会将其用作开发/原型设计黑客并在生产中提出更强大/更安全的东西;诸如视图或存储过程之类的东西。

【讨论】:

  • 但是我们如何为子表构造子数组,因为我们得到重复的结果。
  • @CoderX 不确定你所说的“重复结果”是什么意思,你想在Stack Overflow Chat 中继续讨论吗(实际上,也不确定它是如何工作的)?
  • 我得到以下结果:[ { "userTime": "14:00", "id": 1, "name": "Jack", "Category.id": 11, "Category.name": "Category1", "Category.userID": 1}, { "userTime": "14:00", "id": 1, "name": "Jack", "Category.id": 12, "Category.name": "Category2", "Category.userID": 1 } ] 但我想将结果显示如下:[ { "userTime": "14:00", "id": 1, "name": "Jack", Category: [ { id: 11, name: "Category1", userID: 1 }, { id: 12, name: "Category2", userID: 1 } ] } ]
  • 是的,这就是原始查询之类的问题;数据将作为平面表返回。您将不得不破解您自己对 JS 对象的转换,或者使查询/视图/存储的过程返回与您预期的结构相匹配的 json(b) 值。这几乎是一团糟。可以进行原型设计,但对于生产而言,您需要一个更好的解决方案,以匹配您项目的“大局”。
  • @AlexanderF。 I ended up solving my problem using Postgres views as a workaround. 您是否能够在带有 where 子句(过滤和分页)的视图上使用 findAndCountAll。如果是这样,您是否可以分享一些我试图从 2 天开始实现它并尝试了几乎所有记录在案的方法的片段。谢谢
【解决方案2】:

对于最终在这里使用谷歌搜索的任何人:有一个解决方法,不确定它当时是否可用,但从 5.21.7 开始它可以工作。 您可以传递关联对象以包含参数:

const res = await bank.findAll({
        include: [
            {
                model: account,
                association: new HasMany(bank, account, {/*options*/}),
            },
        ],
    })

HasMany 是一个关联构造函数,可以取自 Sequelize.Associations 或 sequelize 实例。那里还有其他关联构造函数。对于 TS,您需要手动转换,因为该属性不在类型中。

UPD:对于 BelongsToMany,您需要致电 _injectAttributes() 了解关联之前的使用情况,除了 HasMany 之外,我没有检查其他人。

【讨论】:

  • 嘿@Karabur。感谢您的回答!您能否提供一些文档链接(或简短摘录)?自从我不得不处理 Sequelize-js 以来已经有一段时间了,所以您可能对现在的工作方式有了更好的了解。
  • 没有关于那个的文档,我发现它正在寻找续集代码。但是还有更简单更好的方法,您可以定义关联并明确告诉 sequelize 不要在关联选项中使用 constraints: false 在 db 中创建关联。sequelize.org/master/class/lib/… 这样您可以在代码中定义关联但不在 db 中定义关联,因此您将能够以常规方式编写include 语句,让 sequelize 生成连接,但它不会在数据库中创建真正的外键。在 v5 中工作,不了解 v6
  • 根据文档,constraints 应该执行以下操作:Should on update and on delete constraints be enabled on the foreign key. 我设置了 constraints: false 并且能够使用 hasOne 关联来执行包含,而无需实际创建外键数据库。尽管如此,该文档对constraints 的使用说明了一些不同的内容
  • 我只是想建立在答案的基础上,因为我遇到了类似的要求。我不知道是因为 TypeScript 还是 sequelize 版本 6,但我不得不使用 new HasMany(...) 而不是 this.hasMany(OtherModel, {/*options*/}
  • @Karabur thx 百万人...拯救了我的一天!!!! constraints: false 是灵丹妙药 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-09
相关资源
最近更新 更多