具有 nil 值的 Ecto 查询组合
Ecto Query composition with nil values
我有一个带有 where 条件的查询。 where 条件中的某些值可能为 nil,因此不应查询。我想出了这样的模式匹配和自定义函数:
defp add_country(query, nil), do: query
defp add_country(query, country_id), do: from a in query, where: a.country_id == ^country_id
defp add_port(query, nil), do: query
defp add_port(query, port_id), do: from a in query, where: a.port_id == ^port_id
是否有更简单/更清洁的解决方案?我可以在查询本身中完成吗?也许有一个选项?
仅供参考:查询函数:
def list_ads(%{"country_id" => country_id, "port_id" => port_id, "category_id" => category_id}) do
today = Date.utc_today()
query = (from a in Ad,
where: a.category_id == ^category_id,
join: c in Contract,
where: a.contract_id == c.id and
c.payment_status == "PAID" and
c.expiration >= ^today,
distinct: [a.user_id, a.plan],
order_by: a.plan)
|> add_country(country_id)
|> add_port(port_id)
Repo.all(query)
end
请不要因为其中的 "Ad" 这个词而气馁。这些纯粹是信息性的,只显示在平台上,人们会来寻找它们。
我有一个非常相似的问题。如果保存它的值的变量不是 nil
,我需要向我的查询添加过滤器。我最初是在做一堆如果。类似于:
query = if value do
from(q in query, where: q.value == ^value)
else
query
end
这重复了很多次。然后我发现了 field/2
函数。有了它,我能够动态指定我想要比较的字段。所以我构建了一个函数让我重用这个逻辑:
defp put_filter(query, _key, nil) do
query
end
defp put_filter(query, key, value) do
from(q in query, where: field(q, ^key) == ^value)
end:
用法如下:
query =
base_query
|> put_filter(:status, status)
|> put_filter(:reason, reason)
我有一个带有 where 条件的查询。 where 条件中的某些值可能为 nil,因此不应查询。我想出了这样的模式匹配和自定义函数:
defp add_country(query, nil), do: query
defp add_country(query, country_id), do: from a in query, where: a.country_id == ^country_id
defp add_port(query, nil), do: query
defp add_port(query, port_id), do: from a in query, where: a.port_id == ^port_id
是否有更简单/更清洁的解决方案?我可以在查询本身中完成吗?也许有一个选项?
仅供参考:查询函数:
def list_ads(%{"country_id" => country_id, "port_id" => port_id, "category_id" => category_id}) do
today = Date.utc_today()
query = (from a in Ad,
where: a.category_id == ^category_id,
join: c in Contract,
where: a.contract_id == c.id and
c.payment_status == "PAID" and
c.expiration >= ^today,
distinct: [a.user_id, a.plan],
order_by: a.plan)
|> add_country(country_id)
|> add_port(port_id)
Repo.all(query)
end
请不要因为其中的 "Ad" 这个词而气馁。这些纯粹是信息性的,只显示在平台上,人们会来寻找它们。
我有一个非常相似的问题。如果保存它的值的变量不是 nil
,我需要向我的查询添加过滤器。我最初是在做一堆如果。类似于:
query = if value do
from(q in query, where: q.value == ^value)
else
query
end
这重复了很多次。然后我发现了 field/2
函数。有了它,我能够动态指定我想要比较的字段。所以我构建了一个函数让我重用这个逻辑:
defp put_filter(query, _key, nil) do
query
end
defp put_filter(query, key, value) do
from(q in query, where: field(q, ^key) == ^value)
end:
用法如下:
query =
base_query
|> put_filter(:status, status)
|> put_filter(:reason, reason)