2017-04-08 45 views
3

我有一个记录ID列表 - [9, 1, 4, 3]Ecto - 如何按照确切顺序通过ID获取记录

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

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] 

如何检索具有相同顺序的记录?

+0

如果你想在数据库级别上做,那么我没有更好的主意,只能在'order by'语句中使用'case' – JustMichael

回答

4

我不认为有任何简单的方法在数据库中要做到这一点,但这里有一个方式药剂做到这一点:

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 

输出:

[4, 1, 3, 2] 

首先,我们建立id => post的地图。然后,对于ids中的每个ID,如果找到相应的帖子,我们会得到相应的帖子。在我的应用程序中,没有ID为123或456的Post,因此在for中被忽略。

+0

非常感谢! – asiniy

1

您可以使用PostgreSQL的array_position function和Ecto的fragment function。在你的情况下,它看起来像:

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() 

我会避免处理数据库引擎以外的数据。在这个非常简单的例子中,这并不重要。但是,它可能会影响较大数据集或更复杂数据结构的性能,因为首先,必须将结果加载到内存中,然后对它们执行操作以更改顺序。

+1

'idx'函数也可以工作 - https://www.postgresql.org/docs/10/static/intarray.html#id-1.11.7.28.6但这需要'CREATE EXTENSION intarray;' – Ash

相关问题