我的数据库中有“influencer_platforms”
表,其中包含:
id | influencer_handle | name
我想查询它们并按名称分组,例如:
%{
name1: [%{id: 1, influencer_handle: "i1"}, %{id: 3, influencer_handle: "i2"}],
name2: [%{id: 2, influencer_handle: "i3"}]
}
在 Ecto
中如何做到这一点?到目前为止我已经:
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
这是一种更优雅的方式来实现它吗?
最佳答案
如果您希望所有这些都在数据库中完成,您可以将两个片段合并为一个。如果列名是简单常量,您也不需要将列名作为参数传递给 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
获取必要的数据并在 Elixir 中进行分组。这会更优雅,但性能可能会比上面的低,具体取决于 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
关于sql - 如何在 Ecto 中对记录进行分组并将它们作为 map 返回?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44994141/