ActiveRecord AND 查询参数数组

ActiveRecord AND query for array of argumens

我有以下型号:

class Fruit < ApplicationRecord
  has_many :taggings, as: :tagable, dependent: :destroy
  has_many :tags, through: :taggings

class Tagging < ApplicationRecord
      belongs_to :tag
      belongs_to :tagable, polymorphic: true

class Tag < ApplicationRecord
  has_many :taggings, dependent: :destroy
  has_many :fruits,
           through: :taggings,
           source: :tagable,
           source_type: 'Fruit'

假设我有 Fruit 'banana',标签为 'yellow' (id: 182) 和 'long' (id: 168)。我需要一个查询,该查询会给我带有 'yellow' 和 'long' 标签的水果。

香蕉确实有两个标签。

Fruit.find(97).tags
Fruit Load (4.1ms)  SELECT "fruits".* FROM "fruits" WHERE "fruits"."id" =  ORDER BY name LIMIT   [["id", 97], ["LIMIT", 1]]
Tag Load (7.4ms)  SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."tagable_id" =  AND "taggings"."tagable_type" =   [["tagable_id", 97], ["tagable_type", "Fruit"]]

=> [#<标签:0x000000010d50e9d0 编号:168, 名称:“长”, created_at:2021 年 12 月 22 日星期三 16:54:32.290923000 UTC +00:00, updated_at:2021 年 12 月 22 日星期三 16:54:32.290923000 UTC +00:00>, #<标签:0x000000010d50e868 编号:182, 名称:“黄色”, created_at:2022 年 4 月 18 日星期一 16:59:30.244851000 UTC +00:00, updated_at:2022 年 4 月 18 日星期一 16:59:30.244851000 UTC +00:00>]

这样问:

irb(main):063:0> Fruit.joins(:tags).where(tags: { id: [168,182]}).to_sql

会得到我

"SELECT \"fruits\".* FROM \"fruits\" INNER JOIN \"taggings\" ON \"taggings\".\"tagable_type\" = 'Fruit' AND \"taggings\".\"tagable_id\" = \"fruits\".\"id\" INNER JOIN \"tags\" ON \"tags\".\"id\" = \"taggings\".\"tag_id\" WHERE \"tags\".\"id\" IN (168, 182) ORDER BY name"

这是所有 tag.id 168 或 182 的水果。所以不行。

我试过了

Fruit.joins(:tags).where(tags: { id: 168 }).and(where(tags: { id: 182 }))

这将得到空结果。

  Fruit Load (2.0ms)  SELECT "fruits".* FROM "fruits" INNER JOIN "taggings" ON "taggings"."tagable_type" =  AND "taggings"."tagable_id" = "fruits"."id" INNER JOIN "tags" ON "tags"."id" = "taggings"."tag_id" WHERE "tags"."id" =  AND "tags"."id" =  ORDER BY name  [["tagable_type", "Fruit"], ["id", 168], ["id", 182]]
=> []

空。

我也试过了

f = Fruit.joins(:tags)
tags = [168,182]
tags.each do |tag|
f = f.where(tags: {id: tag})
end

  Fruit Load (22.3ms)  SELECT "fruits".* FROM "fruits" INNER JOIN "taggings" ON "taggings"."tagable_type" =  AND "taggings"."tagable_id" = "fruits"."id" INNER JOIN "tags" ON "tags"."id" = "taggings"."tag_id" WHERE "tags"."id" =  AND "tags"."id" =  ORDER BY name  [["tagable_type", "Fruit"], ["id", 168], ["id", 182]]

再次,悲伤的故事,空洞的结果。

请求一个 tag.id 有效,一个或另一个也有效,但我找不到同时请求两个标签并获得结果的方法。

谢谢

您需要的是 SQL GROUP BY,基本上 select 所有具有任一标签的水果,然后按水果 ID 对它们进行分组,并过滤​​所有出现不止一次的水果。据我所知,这不能通过一个 SQL 查询来完成,而是通过两个(一个查询和一个子查询)来完成,这对于 ActiveRecord 来说可能会变得乏味。

如何在 Ruby 中完成大部分艰苦的工作?

fruit = Fruit.joins(:tags).where(tags: { id: [168,182]}).to_a # returns the fruit that have both 2 tags
both_tags_ids = fruit.group_by { |f| f.id }.select { |fruit_id, arr|
    arr.count > 1
}.values.flatten