Ruby on Rails 5:如何查询未关联订单的Product实例?
嘿,我来帮你搞定这个需求!要找出所有没被关联到任何Order的Product实例,结合你给出的模型关联关系,有几种实用的实现方式,我给你一一拆解:
方法一:左外连接 + 空关联筛选(推荐,SQL层面高效处理)
这种方式直接在数据库层面完成筛选,性能最优,适合大部分场景:
Product.left_outer_joins(:orders).where(orders: { id: nil })
原理:left_outer_joins会把每个Product和它关联的Order做左外连接,然后我们筛选出那些没有匹配到Order(也就是orders.id为nil)的产品,这就是完全没被任何订单关联的产品。
方法二:预加载 + Ruby内存过滤(适合小数据量场景)
如果你的产品数据量不大,也可以先预加载所有产品的订单关联,再在Ruby层面过滤:
Product.includes(:orders).reject { |product| product.orders.any? }
原理:includes会一次性加载所有产品及其关联的订单(避免N+1查询),然后用reject去掉那些有至少一个订单关联的产品,剩下的就是目标产品。注意:数据量大的时候这种方式不如SQL层面筛选高效。
方法三:子查询排除已关联ID(高效的SQL子查询方式)
用子查询找出所有已经被订单关联的产品ID,再排除这些ID得到目标产品:
Product.where.not(id: Order.joins(:products).select(:product_id))
原理:先通过Order.joins(:products).select(:product_id)获取所有被任何订单关联过的产品ID集合,然后用where.not排除这些ID,剩下的就是未被关联的产品。这种方式生成的SQL同样高效,适合大数据量场景。
额外说明
如果你的LineItem存在未关联到Order的情况(比如临时购物车项),而你想排除的是没有被任何已完成订单关联的产品,那可以直接关联LineItem来判断:
Product.left_outer_joins(:line_items).where(line_items: { order_id: nil })
不过根据你的模型定义,LineItem是belongs_to :order的,默认情况下LineItem必须关联Order,所以前面的方法已经足够覆盖你的需求啦。
内容的提问来源于stack exchange,提问作者alavni shubham

