1 min read

Ecto assoc to ease join pains

Ecto assoc to ease join pains
Photo by Igor Vymorkov / Unsplash

Let us imagine having the following Ecto entities:

defmodule Meetup do
  schema "meetups" do
    field :name, :string
    field :topic, :string
    ...

    has_many :participants, Participant
    ...
  end
end

defmodule Participant do
  schema "participants" do
    field :name, :string
    field :age, :integer
    ...

    belongs_to :meetup, Meetup
    ...
  end
end

Usually if we want to build an Ecto query to select all participant names at a given meetup with age between 40 and 49, we would do:

from(
    m in Meetup,
    where: m.name == "How to book live, a.k.a. Livebook",
    join: p in Participant,
    on: m.id == p.meetup_id,
    where: p.age >= 40 and p.age <= 49,
    select: p.name
)
|> MyRepo.all()

This could be a tad bit simplified if we use the assoc macro:

from(
    m in Meetup,
    where: m.name == "How to book live, a.k.a. Livebook",
    join: p in assoc(m, :participants),
    where: p.age >= 40 and p.age <= 49,
    select: p.name
)
|> MyRepo.all()

As we can see, instead of knowing the full module name, and the fields that are used to join, we can rely on the relation defined in the schema.

Of course this can work the other way too. Similarly if we want to find all the meetups for a given participant that have a given topic, we can do:

from(
    p in Participant,
    where: p.id == 420,
    join: m in assoc(p, :meetup),
    where: m.topic == "Elixir"
)
|> MyRepo.all()

To close this pill, let me thank the Ecto guys for all their hard work, and for the best framework (to work with databases and queries) that I have ever used. It offers productivity, maintainability, and performance out of box and it never let me down like most of the other similar frameworks from other programming languages.