I have been getting into Elixir from the Ruby on Rails world.
I have the following table:
release_track_id | release_id | track_id | release_side_id | track_number
------------------+------------+----------+-----------------+--------------
347 | 70 | 211 | 3 | 1
329 | 70 | 193 | 1 | 1
356 | 70 | 220 | 4 | 1
338 | 70 | 202 | 2 | 1
357 | 70 | 221 | 4 | 2
330 | 70 | 194 | 1 | 2
348 | 70 | 212 | 3 | 2
339 | 70 | 203 | 2 | 2
331 | 70 | 195 | 1 | 3
349 | 70 | 213 | 3 | 3
358 | 70 | 222 | 4 | 3
So far the query to pull that works great:
query = from at in ReleaseTrack,
distinct: true,
join: s in ReleaseSide, on: [release_side_id: s.release_side_id],
join: a in Release, on: [release_id: at.release_id],
where: a.active == true,
where: at.release_id == ^release_id,
Repo.all(query)
I get all those rows perfectly.
However, I want to transform what gets outputted:
[
%App.ReleaseTrack{
__meta__: #Ecto.Schema.Metadata<:loaded, "release_tracks">,
inserted_at: ~N[2021-05-26 00:30:34],
release_id: 70,
release_side_id: 1,
release_sides: %App.ReleaseSide{
__meta__: #Ecto.Schema.Metadata<:loaded, "release_sides">,
inserted_at: ~N[2021-05-26 00:30:34],
order_number: 1,
release: #Ecto.Association.NotLoaded<association :release is not loaded>,
release_id: 70,
release_side: "Disc 1",
release_side_id: 1,
updated_at: ~N[2021-05-26 00:30:34]
},
release_track_id: 329,
track: %App.Track{
__meta__: #Ecto.Schema.Metadata<:loaded, "tracks">,
track_id: 211,
bpm: 60,
title: "Ghosts",
...
}
],
...
What I would like to do is to transform the Repo.all
into something like this:
%{ 70 => [track1, track2, track3] %}
If release_side_id
pointed to Disc 1
, as in the output above, and [track1, track2, track3]
represents each of the %App.Track{}
result.
Essentially, a keyword pair looking at the table:
%{ release_side_id => [track_id data, track_id data] }
No matter what I can't do, I can't get it to work. In a Ruby world:
tracks = {}
results.each do |result|
side_name = result["release_side_id"]
tracks[:release_side_id] ||= []
tracks[:release_side_id] << results["track_id"]
end
I know Elixir does not keep track of the state of these variables, hence this issue, but there has to be a clever way using map
or reduce
...?
Thank you
Enum.group_by
should help:
Repo.all(query)
|> Enum.group_by(fn x -> x.release_id end, fn t -> t.track end)