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

时间:2014-06-13 23:41:54

标签: ruby select activerecord ruby-on-rails-4

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

由于我的数据库已增长到大约10k卡,我的搜索功能异常缓慢,因为我有一个带有查询的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

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

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

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

返回错误

  

ActiveRecord :: StatementInvalid:PG :: SyntaxError:ERROR:语法错误   在或附近" SELECT"第1行:... id"在哪里"卡"。" id" IN(2,3,4)和   (colors = SELECT" co ...

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

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

2 个答案:

答案 0 :(得分:1)

  

我需要只能搜索绿黑卡片,而不会出现单绿色或绿黑红色的卡片。

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

我玩了一点,我没有使用聚合函数就看不到任何解决方案。 对于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可能是一个错误的格式化程序,无论如何你必须注意按字母顺序聚合颜色。只要你没有太多卡片它就足够慢,但它会扫描表格中的每张卡片。

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

答案 1 :(得分:0)

试试这个

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