sql - 如何在 Ecto 中对记录进行分组并将它们作为 map 返回?

标签 sql postgresql elixir ecto

我的数据库中有“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/

相关文章:

elixir - Ecto 查询中正则表达式的正确语法是什么?

sql - Postgresql:更新问题

mysql - 如何根据日期选择列的总和

php - 使用 php 和 mysql 存储和检索多维数组

sql - 更改名为 'xxx' 的每一列

sql - 无法在 Postgres (9.3) 索引中使用 concat 函数

sql - 是否有任何规则或文档可用于 Oracle 数据库选择语句的列名的输出名称?

ruby-on-rails - rails 3,Heroku : Taps Server Error: PGError: ERROR: invalid byte sequence for encoding "UTF8": 0xba

json - 在 iex 中运行 elixir poison 命令

database - 自定义ecto迁移主键并自动生成