使用动态数量的where过滤器编写Ecto [v1]查询

时间:2015-09-27 23:02:19

标签: elixir ecto

这是一个理论问题,但假设数据结构不能改变,这绝对是我们想要进行查询的方式。这个问题更多是为了更好地理解如何动态组合where过滤器,而不是真正想要从这样的查询中获取结果。

想象一下带有Car表的数据库,其中每辆车都有一个manufacturer_id列,其中包含一个ID,例如“BD324”或“GM512”,其中包含“BD”和& “GM”被视为前缀。

我们需要在car table上进行查找,以便当他们的manufacturer_id前缀与给定的一组前缀匹配时返回汽车。所以,给出一个前缀列表:

prefixes = ["BD", "GM", "EX", "RD", "DE"]

..我们希望退回所有manufacturer_id任何列出的车辆的车辆。即(如x OR 喜欢 OR 喜欢z)。

以下Elixir / Ecto代码将搜索一个前缀:

search_prefix = Enum.at(prefixes, 0) <> "%"
from c in Car, where: like(c.manufacturer_id, ^search_prefix)

我们如何根据where列表构建prefixes子句?

2 个答案:

答案 0 :(得分:4)

Ecto似乎缺乏一种简单的方法来加入查询的动态部分OR,但我可能错过了一些东西。如果我错了,请纠正我。

但是,您可以使用等效的ANY查询,我声称该查询更易于阅读且更易于构建:

SELECT * from cars
 WHERE manufacturer_id LIKE ANY(ARRAY['BD%', 'GM%', 'EX%', 'RD%', 'DE%']);

要使用Ecto创建此类查询,您可以使用fragment

prefixes_like = prefixes |> Enum.map(&"#{&1}%")
from c in Car,
  where: fragment("? LIKE ANY(?)", c.manufacturer_id, ^prefixes_like),
  select: c

答案 1 :(得分:4)

您可以将组合查询视为数据转换:

prefixes -> query with multiple where conditions

为此,您需要将一种数据结构减少到另一种数据结构,而Ecto 2提供符合您需求的or_where

以下是一个例子:

def filter_by_prefixes(query, prefixes) do
  Enum.reduce prefixes, query, fn prefix, query ->
    filter_by_prefix(query, prefix)
  end
end

def filter_by_prefix(query, prefix) do
  or_where(query, [c], like(c.manufacturer_id, ^"#{prefix}%"))
end

# Then build the query
Car |> filter_by_prefixes(prefixes)