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
我有以下型号:
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