2017-04-08 12 views
3

私はレコードIDのリストを持っています - [9, 1, 4, 3]Ecto - 正確な順序でIDでレコードを取得する方法

私は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] 

同じ順序でレコードを取得するにはどうすればよいですか?

+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の地図そして、各IDがidsであれば、それが見つかった場合に対応するPostを取得します。私のアプリでは、ID 123または456の投稿はありませんでしたので、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

関連する問題