Search code examples
sqlelixirphoenix-frameworkecto

Is there a way to iterate over a list of attributes to select in an Ecto query?


So, I have a query that I'm trying to construct where there's a list attributes which are columns on a table. This query is to group by the list of attributes, count, and return the count with the list of attributes. That last part is what I've had the trouble achieving. Right now I have

defmodule ProjectName.Counter do
  import Ecto.Query, only: [group_by: 3, select: 3]

  def group_and_count(queryable, groups) do
    queryable
    |> group_by([q], ^groups)
    |> select([q], count(q.id))
  end
end

Which I invoke as such in a context

Track
|> Counter.group_and_count([:album, :artist])
|> Repo.all()

Which returns me [1, 5, 4, 2] which is correct however, not what I'd like it to return. I'd like to actually have the query

SELECT COUNT(*), tracks.album, tracks.artist FROM tracks GROUP BY tracks.album, tracks.artist

which would return

[[1, "Calypso", "Harry Belafonte"],
 [5, "Silk & Soul", "Nina Simone"],
 [4, "Hello, Dolly!", "Louis Armstrong"],
 [2, "Pure Gold", "Perry Como"]]

How can I change my code to make this work? I can't figure out a way to iterate over groups within the select query.


Solution

  • There's probably a much better way of doing it, but it looks like map/2 and struct/2 are made to support passing in lists.

    It's ugly, but you could just select a tuple containing a map and the count:

    |> select([q], {map(q, ^groups), count(q.id)})