ruby-on-rails - 给定两个链接的 HABTM 和 has_many 关系,优化 ActiveRecord 查询以排除某些项目
问题描述
我需要通过过滤器仅显示 ActiveAdmin 中的一个表中的某些条目,我将其实现为选择(下拉)并且其代码在 Rails 范围内。我很难在 Rails 范围内找到以下条件的纯 SQL 替代品。
我有以下型号:
# app/models/score.rb
class Score < ApplicationRecord
has_and_belongs_to_many :export_orders, join_table: :scores_export_orders
end
# app/models/export_order.rb
class ExportOrder < ApplicationRecord
has_and_belongs_to_many :scores, join_table: :scores_export_orders
belongs_to :shop
end
# app/models/shop.rb
class Shop < ApplicationRecord
has_many :export_orders
end
过滤器允许您选择商店,因此相关代码需要在范围内返回 a Score::ActiveRecord_Relation
。
条件是:返回所有未导出到选定店铺的分数,即所有没有出口订单的分数shop
等于选定店铺。
例如,想象以下场景:
[608, []]
[607, []]
[606, []]
[593, [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, 1, 8, 8, 8, nil, nil, nil, nil, 8, 8]]
[586, []]
[585, []]
[372, [nil, nil, 2, nil, nil, nil, 8, 8, 8, nil]]
[157, [nil, 2, nil, nil, nil, 1]]
左边是分数 ID,右边是他们出口订单的商店 ID 数组。需要明确的是,以上是 的结果Score.all.map { |s| [s.id, s.export_orders.map{|o|o.shop_id}] }
。
例如,结果Score.not_exported_to(2).ids
应该是
[608, 607, 606, 593, 586, 585]
因为分数的出口订单(带有这些 id)都没有2
在他们的商店 id 中。
现在,我真的想不出用 SQL 的方式来写这个。到目前为止,我在我的范围内拥有的是:
# app/models/score.rb
scope :not_exported_to, -> (input) {
shop = Shop.find(input)
export_orders = shop.export_orders
already_exported_score_ids = export_orders.map { |o| o.scores.ids } .flatten.uniq
where.not(id: already_exported_score_ids)
}
这给出了正确的结果,但显然效率很低,因为它使用map
依赖关联 ( Score
),它在分数表上执行选择,重复次数等于export_orders.count
。想象一下它在一家商店的 1000 多个出口订单上运行!
到目前为止我尝试了什么:
joins("INNER JOIN scores_export_orders ON scores.id = scores_export_orders.score_id INNER JOIN export_orders ON export_orders.id = scores_export_orders.export_order_id").distinct.where("export_orders.shop_id <> #{input}")
但这会返回错误的结果。
我在 SQL 方面不是那么专家,恐怕我不得不使用某种我不太熟悉的嵌套查询。
解决方案
推荐阅读
- yocto - 向 Raspberry Yocto 项目添加新的 dts
- ms-word - Office 2013 的带有功能区按钮的 Office 插件清单
- sql - 左连接会导致性能大幅下降。如何修复它
- c# - 如何从给定路径中删除文件和文件夹
- python - 如何在 Pandas Dataframe 中将行转换为列
- flutter - 从 google_maps_flutter 中删除多余的标记和圆圈
- angular - Angular 7 openlayers 项目适用于除 edge 和 ie 之外的所有浏览器
- laravel - Laravel where 条件不适用于查询 WITH 关系
- r - 如何将数据集中的每六行替换为从第 7 行开始的滞后
- python - Is there a Python technique for loading object variables as needed?