【问题标题】:Search for model by multiple join record ids associated to model by has_many in rails通过rails中的has_many关联到模型的多个连接记录ID搜索模型
【发布时间】:2016-05-13 12:43:39
【问题描述】:

我的产品模型设置如下:

class Product < ActiveRecord::Base
  has_many :product_atts, :dependent => :destroy
  has_many :atts, :through => :product_atts
  has_many :variants, :class_name => "Product", :foreign_key => "parent_id", :dependent => :destroy
end

我想搜索与多个属性关联的产品。

我想也许这会起作用:

Product.joins(:product_atts).where(parent_id: params[:product_id]).where(product_atts: {att_id: [5,7]})

但这似乎并不符合我的要求。这在 ID 或 ID 处执行。

所以我尝试了以下方法:

Product.joins(:product_atts).where(parent_id: 3).where(product_atts: {att_id:  5}).where(product_atts: {att_id:  7})

但这也不起作用,它返回 0 个结果。

所以我的问题是如何通过传入相同模型类型的多个连接模型的属性来查找模型?

解决方案:

 att_ids = params[:att_ids] #This is an array of attribute ids
 product = Product.find(params[:product_id]) #This is the parent product
 scope = att_ids.reduce(product.variants) do |relation, att_id|
   relation.where('EXISTS (SELECT 1 FROM product_atts WHERE product_id=products.id AND att_id=?)', att_id)
 end

 product_variant = scope.first

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3 postgresql activerecord


    【解决方案1】:

    这是一个看似简单的请求,但由于 SQL 的工作原理,它实际上非常棘手。连接总是只是将 rows 连接在一起,而您的 WHERE 子句一次只会查看 一个 行(因此为什么您的期望没有像您期望的那样工作 - - 一行不可能有同一列的两个值。

    在处理原始 SQL 时有很多方法可以解决这个问题,但在 Rails 中,我发现最简单(不是最有效)的方法是使用 EXISTS 关键字嵌入子查询。将其包装在处理任意数量的所需 att_id 的解决方案中,您将得到:

    scope = att_ids_to_find.reduce(Product) do |relation, att_id|
      relation.where('EXISTS (SELECT 1 FROM product_atts WHERE parent_id=products.id AND att_id=?)', att_id)
    end
    
    products = scope.all
    

    如果您不熟悉reduce,那么它会采用Product,然后为每个att_id 添加一个额外的where 子句。最终结果类似于Product.where(...).where(...).where(...),但您不必担心太多。当与范围和其他连接混合使用时,此解决方案也很有效。

    【讨论】:

    • 虽然我喜欢在这里学习一些新东西,但该解决方案似乎不起作用。我用 product.variants 和 att_ids_to_find = [6,11] 替换了 Product。即使存在具有这两种关系的产品,它也会返回 0 个结果。
    • 查询结果如下:SELECT "products".* FROM "products" WHERE "products"."parent_id" = $1 AND (EXISTS (SELECT 1 FROM product_atts WHERE parent_id=products.id AND att_id=6)) AND (EXISTS (SELECT 1 FROM product_atts WHERE parent_id=products.id AND att_id=11)) [["parent_id", 3]]
    • 我刚刚意识到“parent_id”应该是“product_id”,哎呀。
    • 太棒了!查询和解决方案本身当然取决于您的架构,我主要是在猜测;很高兴您能够自己找到完整的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2013-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 2018-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多