将数组#select转换为rails 4中的活动记录查询

我正在编写自定义搜索function,我必须通过关联进行过滤。 我有2个活动记录支持的模型,卡片和颜色带有has_many_and_belongs_to,颜色有属性color_name

由于我的数据库已经增长到大约10k卡,我的搜索function变得exception缓慢,因为我有一个带有查询的select语句,所以基本上我不得不进行数千次查询。

我需要将数组#select方法转换为活动记录查询,这将产生相同的结果,并且我无法提出解决方案。 当前(相关代码)如下:

colors = [['Black'], ['Blue', 'Black']] #this is a parameter retrieved from a form submission if color cards = color.flat_map do |col| col.inject( Card.includes(:colors) ) do |memo, color| temp = cards.joins(:colors).where(colors: {color_name: color}) memo + temp.select{|card| card.colors.pluck(:color_name).sort == col.sort} end end end 

我试图模仿的function是只搜索具有与传入数组完全匹配的颜色的卡(比较两个数组)。 因为卡可以是单红,红蓝或红蓝绿等,我需要能够只搜索红蓝卡或只搜索单红卡

我最初是沿着这条路线开始的,但是我在将数组与活动记录查询进行比较时遇到了麻烦

 color_objects = Color.where(color_name: col) Card.includes(:colors).where('colors = ?', color_objects) 

返回错误

ActiveRecord :: StatementInvalid:PG :: SyntaxError:ERROR:“SELECT”处或附近的语法错误第1行:… id“WHERE”cards“。”id“IN(2,3,4)AND(colors = SELECT”共…

它看起来像它失败,因为它不想比较数组,只有表格元素。 这个function甚至可能吗?

一种解决方案可能是将habtm转换为具有多个关系,并创建包含每个颜色排列的键的连接表,以便直接访问这些颜色

我需要能够只搜索绿黑卡片,而不会显示单绿色或绿黑红色卡片。

我删除了我的普遍答案,因为我没有意识到你正在寻找完全匹配。

我玩了一点,没有使用聚合函数我看不到任何解决方案。 对于Postgres,它将是array_agg 。

您需要生成一个SQL查询,如:

 SELECT *, array_to_string(array_agg(colors.color_name), ',')) as color_names FROM cards JOINS cards_colors, colors ON (cards.id = cards_colors.card_id AND colors.id = cards_colors.color_id) GROUP BY cards.id HAVING color_names = 'green, black' 

我从来没有使用过那些聚合器,所以也许array_to_string是一个错误的格式化程序,无论如何你必须注意按字母顺序聚合颜色。 只要你没有太多卡片就足够慢,但它会扫描桌子上的每张卡片。

我想在此查询中使用索引,您应该对数据结构进行非规范化,在卡片记录上使用color_names数组 ,索引该数组字段并对其进行搜索。 您还可以保持规范化结构并定义自动关联回调 ,每次将颜色分配给卡时,都会将颜色名称放入卡的color_names数组中。

试试这个

 colors = Color.where(color_name: col).pluck(:id) Card.includes(:colors).where('colors.id'=> colors)