2017-07-09 2 views
2

私はで構成され、私のDBで"influencer_platforms"のテーブルを持っている:Ectoでレコードをグループ化してマップとして返​​すにはどうすればいいですか?

id | influencer_handle | name 

私はのような名前で、グループを照会したい:Ectoでそれを行うにはどうすればよい

%{ 
    name1: [%{id: 1, influencer_handle: "i1"}, %{id: 3, influencer_handle: "i2"}], 
    name2: [%{id: 2, influencer_handle: "i3"}] 
} 

?これまでのところ、私は持っています:

defmacrop influencer_platform_json(influencer) do 
    quote do 
    fragment(
     "jsonb_agg(?)", 
     fragment(
     "json_build_object(?, ?, ?, ?)", 
     "id",    unquote(influencer).id, 
     "influencer_handle", unquote(influencer).influencer_handle 
    ) 
    ) 
    end 
end 

def all do 
    from ip in InfluencerPlatform, 
    group_by: :name, 
    select: %{ 
     ip.name => influencer_platform_json(ip) 
    } 
end 

それを達成するためのよりエレガントな方法はありますか?

+1

'' influencer'を複数回引用符で囲むのを避けるために 'bind_quoted'を使用するとよいでしょうか? –

+0

@MikeBuhot私はそれが 'fragment'の仕事であるかどうか分かりません。 – squixy

答えて

2

これをすべてデータベースで実行したい場合は、2つのフラグメントを1つにまとめることができます。単純な定数の場合は、列名をfragmentの引数として渡す必要はありません。クエリ内の列名をfragmentに入れることができます。

defmacrop influencer_platform_json(influencer) do 
    quote do 
    fragment("jsonb_agg(jsonb_build_object('id', ?, 'influencer_handle', ?))", unquote(influencer).id, unquote(influencer).influencer_handle) 
    end 
end 

また、必要なデータをフェッチし、エリクサーでEnum.group_by/2を使用してグループを行うことができます。これははるかに優雅ですが、PostgreSQLのJSON処理が上記のクエリにどのように最適化されているかに依存して、上記より性能が劣る可能性があります。

from(ip in InfluencerPlatform, select: map(ip, [:id, :name, :influencer_handle])) 
|> Repo.all 
|> Enum.group_by(fn ip -> ip.name end) 
# Delete `:name` from each map. 
|> Enum.map(fn {k, v} -> 
    {k, Enum.map(v, &Map.delete(&1, :name))} 
end) 
|> Map.new 
関連する問題