Ecto - 如何按照确切的顺序获取ID记录

asi*_*niy 4 elixir ecto phoenix-framework

我有一个记录ID列表 - [9, 1, 4, 3].

我想从postgresql中检索记录,并希望它们按照此ID列表进行排序.但是当我进行查询时,记录以任意顺序返回:

Ecto.Query.from(r in Record, where: r.id in [9, 1, 4, 3]) 
  |> Repo.all()
  |> Enum.map(&Map.get(&1, :id)) # => [4, 9, 1, 3]
Run Code Online (Sandbox Code Playgroud)

如何检索具有相同订单的记录?

sme*_*fju 7

您可以使用PostgreSQL的array_position函数和Ecto的片段函数.在您的情况下,它看起来像:

Ecto.Query.from(r in Record, where: r.id in [9, 1, 4, 3])
  |> Ecto.Query.order_by([r], fragment("array_position(?, ?)", [9, 1, 4, 3], r.id) 
  |> Repo.all()
Run Code Online (Sandbox Code Playgroud)

我会避免在数据库引擎之外处理数据.在这个非常简单的例子中应该没关系.但是,它可能会对更大的数据集或更复杂的数据结构的性能产生影响,因为首先,您必须将结果加载到内存中,然后对它们执行操作才能更改顺序.


Dog*_*ert 5

我认为在数据库中没有任何简单的方法可以做到这一点,但这里有一种在 Elixir 中做到这一点的方法:

ids = [123, 4, 1, 3, 2, 456]
posts = from(p in Post, where: p.id in ^ids, select: {p.id, p}) |> Repo.all |> Map.new
posts = for id <- ids, posts[id], do: posts[id]
posts |> Enum.map(&(&1.id)) |> IO.inspect
Run Code Online (Sandbox Code Playgroud)

输出:

[4, 1, 3, 2]
Run Code Online (Sandbox Code Playgroud)

首先,我们建立一个地图id => post。然后,对于 中的每个 id ids,如果找到了相应的 Post,我们将获得相应的 Post。在我的应用程序中,没有 ID 为 123 或 456 的 Post,因此它们在for.