【问题标题】:Rails filter by multiple nested recordsRails 按多个嵌套记录过滤
【发布时间】:2021-05-08 14:39:54
【问题描述】:

使用 Ruby on Rails 5,假设我有两个模型,图像和颜色。每个图像有_many 颜色,每个颜色有_many 图像。

现在我尝试获取包含红色和蓝色的图像:

Image.joins(:colors).where(colors: {name: 'red'}).where(colors: {name: 'blue'})

我知道有些图像包含红色和蓝色,但上面的行总是返回 nil。当我这样做时

Image.joins(:colors).where(colors: {name: 'red'}).first.colors

它包含蓝色。

我的错误在哪里?

【问题讨论】:

  • 您没有得到任何结果,因为根据您的关系定义,一张图像可以有多种颜色,因此一种颜色是连接表中的一行,并且您正在过滤与相同列匹配的行但是一次有两个不同的值,这样的任何查询都不会返回任何结果。您可能需要为此调整查询。

标签: ruby-on-rails database nested


【解决方案1】:

正如 Sebastian Palma 在他的评论中已经解释的那样:您不会得到任何结果,因为连接中的一条线可以具有红色或蓝色,但不能同时具有两种颜色。

在您的示例中,您需要选择所有具有红色或蓝色的线条,然后您需要再次按图像对这些线条进行分组,然后仅返回找到至少两种颜色的图像。

Image
  .select('images.*, COUNT(colors.id)')
  .joins(:colors)
  .where(colors: { name: ['red', 'blue'] })
  .group('images.id')
  .having('COUNT(colors.id) >= 2')

【讨论】:

  • 我想知道选择是否是必要的,或者可以像帕斯卡的回答那样省略
  • 选择很有用,否则返回的图像将包含颜色值。并且根据您的数据库引擎,当您尝试使用 HAVING COUNT 而不将 COUNT 包含在 SELECT 中时,它可能会抱怨。
  • 是的,我想知道如果你忽略它,activerecord 是否会为你做这件事
  • .where(colors: { name: ['red', 'blue'] }) 返回颜色为红色或蓝色的所有图像。当我最后计算 color.id 时,我怎么能确定它包含“红色”和“蓝色”(可能还有其他颜色)但不是“绿色”而不是“红色”或“蓝色”?
  • 您可以确定,因为您只选择红色或蓝色的记录,然后计算有多少。因为您只选择了这两种颜色,所以当有 2 条记录时,它必须正是这两种颜色。
【解决方案2】:

您可以将这样的方法添加到您的 Image 模型中:

  def self.only_colors(clrs)
    Image
      .joins(:colors)
      .where(colors: {name: clrs})
      .group("images.id")
      .having("count(*) = ?", clrs.size)
  end

(或创建对应的scope)

假设有两张图片,一张只有蓝色,一张有蓝色和红色,join和where将导致:

image name                       |  color
------------------------------------------------------
study in red and blue            | red
study in red and blue            | blue
feeling blue                     | blue

通过按images.id 列对行进行分组,然后按您要匹配的颜色数过滤这些分组的行 (having),您将只获得具有两种颜色的图像。

由于 where 条件,您将只连接与颜色匹配的行(红色 OR 蓝色)。当您应用带有颜色数量的 having 子句(类似于 where 但对于 group by)时,您实际上是在转动 OR 变成 AND

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 2023-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多