Sequelize - 使用包含向查询添加限制,无法正确限制检索

Sequelize - Adding a limit to a query with an include, fails to properly limit retrievals

问题描述

使用子查询向 Sequelize 查询添加限制无法限制检索。引用此错误的多个在线资源都没有解决方案。这是 Sequelize 错误还是用户错误?

你在做什么?

ThreadFolderUser.findAll({
order: [
  ['updated_at', 'DESC']
],
where: {
  user_id,
  folder_id,
  deleted,
  archived,
},
distinct: true,
offset,
limit: 10,
include: [
  {
    model: Thread,
    include: [
      { model: Email, include: [Attachment] },
    ]
  }
],

})


协会

// ThreadFolderUser (assoc table) - Thread / Folder / User (tables)
User.hasMany(ThreadFolderUser, { foreignKey: 'user_id' })
ThreadFolderUser.belongsTo(User, { foreignKey: 'user_id' })
Folder.hasMany(ThreadFolderUser, { foreignKey: 'folder_id' })
ThreadFolderUser.belongsTo(Folder, { foreignKey: 'folder_id' })
Thread.hasMany(ThreadFolderUser, { foreignKey: 'thread_id' })
ThreadFolderUser.belongsTo(Thread, { foreignKey: 'thread_id' })

// Thread - Emails
Thread.hasMany(Email, { foreignKey: 'thread_id' })
Email.belongsTo(Thread, { foreignKey: 'thread_id' })

// Email - Attachments
Email.hasMany(Attachment, { foreignKey: 'email_id' })
Attachment.belongsTo(Email, { foreignKey: 'email_id' })

你预计会发生什么?

我预计从 AssociationTable 中检索到 10 条记录(基于当前设置为 10 的限制),因为我在数据库中至少有 15 条记录与此查询匹配。

实际发生了什么?

Returns 在我的例子中是 6,而不是 10(限制设置为 10)。而不是拉前 10 场比赛。


其他上下文

如果我删除 limit,它将按预期工作(即使有包含)。

如果我删除 include,它将按预期工作(即使有限制)。

如果我 copy/paste Sequelize 生成的 SQL 查询并将其直接插入 Workbench,它会检索适当数量的行。

问题似乎是 limitinclude 相结合导致查询仅检索前 10 个匹配的记录在数据库中搜索。


对同一问题的其他引用,但没有提供适当的解决方案:


环境


我很清楚这个完全相同的问题已经在多个其他线程和平台中提出——正如我在上面链接的一些——但是 none 其中有一个直接的答案, 其中 1 个将不相关的点标记为未解决预期问题的答案。我希望我们能得到这个问题的答案,或者除了硬编码 SQL 查询(最后的手段)之外的现实解决方法。

Sequelize 无法处理包含在同一查询中的限制是不可想象的,所以我这边一定有什么遗漏/用户错误。我已经搜索了多次,当然是从 Sequelize 文档开始的,其中没有提到这个问题或类似的例子,也没有提到结合限制和包含可能出现的任何问题。

非常感谢您为帮助解决此问题所做的任何贡献。希望有 @Sequelize 工程师能够帮助回答这个问题 :)

您无法正确限制包含 hasMany 关联的 sequelize 查询,直到您通过单独的查询进行 sequelize 以获取包含的关联对象。在您的查询中,您有 include 与关联 Thread.hasMany(Email 因此您应该指明 separate: true 在电子邮件中包含这样的内容(这也适用于附件关联):

include: [
      { 
       model: Email, 
       separate: true,
       include: [{
         model: Attachment,
         separate: true
       }] },
    ]

另外你不需要指明 distinct: true 因为我们已经指明将 hasMany 关联分离到它自己的查询中。

hasMany 的另一个问题 includes(尤其是嵌套的 hasMany)在查询中 它们在 SQL 查询中变成 JOIN,这意味着数据库将一定数量的主记录乘以一定数量的嵌套记录,依此类推。 例如:100 条主记录,每条记录都有 100 条链接记录,每条记录都有自己的 100 条链接记录(线程 -> 电子邮件 -> 附件)。总而言之,您创建了一个数据库来一次查询 100*100*100 - 100 万条记录!通常会导致内存不足

关于 LIMIT 和 hasMany:数据库选择 100 个主记录,每个主记录有 100 个链接(一次 10000 条记录),然后从这 10000 条记录中获取前 10 条记录(而不是从 100 条主记录中)。这就是 SQL 查询的工作原理!