Ecto query call when using aggregate function

I found this thread while researching options for adding aggregated results to a list, and would like to propose a different way to do it that doesn’t require any extra mapping or struct building for anyone else looking. Apologies for necro-posting.

First, add a virtual field to the Tag schema:

field :posts_count, :integer, virtual: true

Then simply merge the aggregate result into the existing list of returned structs, which if there is no select in the query it defaults to the full schema (equivalent to select: t.)

def list_tags_with_posts_count do
  Repo.all(
    from t in Tag,
      left_join: p in assoc(t, :posts),
      group_by: t.id,
      order_by: [asc: :name],
      select_merge: %{posts_count: count(p.id)}
  )
end