这是一个理论问题,但假设数据结构不能改变,这肯定是我们想要进行查询的方式.这个问题更多的是为了更好地理解如何where动态组合过滤器而不是实际想要从这样的查询中获取结果.
想象一个带有Car表的数据库,其中每辆车都有一个manufacturer_id包含ID 的列,例如"BD324"或"GM512",其中"BD"和"GM"被视为前缀.
我们需要在汽车表上进行查找,以便当汽车的manufacturer_id前缀与给定的一组前缀匹配时返回汽车.所以,给出一个前缀列表:
prefixes = ["BD", "GM", "EX", "RD", "DE"]
Run Code Online (Sandbox Code Playgroud)
..we'd想返回有所有汽车manufacturer_id与启动任何所列出的那些.即(如x 或类似y 或类似z).
以下Elixir/Ecto代码将搜索一个前缀:
search_prefix = Enum.at(prefixes, 0) <> "%"
from c in Car, where: like(c.manufacturer_id, ^search_prefix)
Run Code Online (Sandbox Code Playgroud)
我们如何where根据prefixes列表建立条款?
您可以将组合查询视为数据转换:
prefixes -> query with multiple where conditions
Run Code Online (Sandbox Code Playgroud)
为此,您需要将一种数据结构简化为另一种数据结构,而 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)
Run Code Online (Sandbox Code Playgroud)
Ecto 似乎缺乏一种简单的方法来连接查询的动态部分OR,但我可能错过了一些东西。如果我错了,请纠正我。
但是,您可以使用等效的ANY查询,我声称它更易于阅读且更易于构建:
SELECT * from cars
WHERE manufacturer_id LIKE ANY(ARRAY['BD%', 'GM%', 'EX%', 'RD%', 'DE%']);
Run Code Online (Sandbox Code Playgroud)
要使用 Ecto 创建此类查询,您可以使用fragment:
prefixes_like = prefixes |> Enum.map(&"#{&1}%")
from c in Car,
where: fragment("? LIKE ANY(?)", c.manufacturer_id, ^prefixes_like),
select: c
Run Code Online (Sandbox Code Playgroud)