在 Elixir 中编写 Ecto 查询

phi*_*hil 4 elixir ecto phoenix-framework

我从客户端传入的参数列表中创建了一个查询列表:

[
  #Ecto.Query<from v in Video, where: v.brand == ^"Cocacola">,
  #Ecto.Query<from v in Video, where: v.type == ^"can">
]
Run Code Online (Sandbox Code Playgroud)

但是,我需要遍历此列表并编写一个查询,该查询是所有查询的累加......(下一个查询的输入是当前查询等。)

有人能指出我如何做到这一点的正确方向。这将不胜感激!

我知道我可以一一撰写查询。但是我从客户端获取参数并且有一长串字段(品牌、类型等),并且不想对每个字段进行单独的查询。

She*_*yar 5

除非您打开单个查询结构并检查它们的底层实现,否则既不可能也不建议像这样在 Ecto 中连接查询。相反,您应该尝试将它们分解并使其可组合。

Ecto 使您可以非常轻松地将查询组合在一起:

defmodule VideoQueries do
  import Ecto.Query

  def with_brand(query, brand) do
    where(query, [v], v.brand == ^brand)
  end

  def with_type(query, type) do
    where(query, [v], v.type == ^type)
  end

  def latest_first(query) do
    order_by(query, desc: :inserted_at)
  end
end
Run Code Online (Sandbox Code Playgroud)

你可以这样称呼它们:

Video
|> VideoQueries.with_brand("Cocacola")
|> VideoQueries.with_type("can")
|> VideoQueries.latest_first
Run Code Online (Sandbox Code Playgroud)



现在假设您获得了一个MapKeyword List多个查询参数并且想要应用它们,您仍然可以通过在运行时迭代键/值来将它们一起调用。您可以构建一个为您执行此操作的过滤器方法:

# Assuming args are a Keyword List or a Map with Atom keys
def filter(query, args) do
  Enum.reduce(args, query, fn {k, v}, query ->
    case k do
      :brand -> with_brand(query, v)
      :type  -> with_type(query, v)
      _      -> query
    end
  end)
end
Run Code Online (Sandbox Code Playgroud)

并且可以动态组合这样的查询:

user_input = %{brand: "Cocacola", type: "can"}

Video
|> VideoQueries.filter(user_input)
|> Repo.all
Run Code Online (Sandbox Code Playgroud)



进一步阅读: