abdelaz3r

abdelaz3r

Load nested association and select count at the same time

Hello.

I have this Ecto Shema:

Instance -> has_many(Faction) -> many_to_many(Profils)

So, instances has many factions, and profils can register into a faction (given an instance).

I would like, when I load instances, to preload their corresponding factions (easy) and to add, for each faction, a field that is the number of registered profil.

First question: I dont know if I need to add a field (virtual?) to the faction schema (such as “registered_profils”).

Second question: How would look like the request?

For now I have this request that works (but it only preload factions into instances and profils into factions):

query =
  from instance in Instance,
    left_join: factions in assoc(instance, :factions),
    left_join: profils in assoc(factions, :profils),
    preload: [factions: {factions, profils: profils}],
    order_by: [desc: instance.id]

I also tried different queries such as:

query =
  from instance in Instance,
    left_join: factions in assoc(instance, :factions),
    left_join: profils in assoc(factions, :profils),
    preload: [factions: {factions, profils: profils}],
    group_by: factions.id,
    select: {factions.registered_profils, count(profils.id)},
    order_by: [desc: instance.id]

But none works for now. Any idea?

First Post!

LostKobrakai

LostKobrakai

You can look at count distinct.

Most Liked

Kurisu

Kurisu

I did something similar sometime ago.
I used a virtual field for the count then make a querry like:

....,
select_merge: %{factions_count: count(factions.id)
....

So your query could look like:

query =
  from instance in Instance,
    left_join: factions in assoc(instance, :factions),
    left_join: profils in assoc(factions, :profils),
    preload: [factions: {factions, profils: profils}],
    order_by: [desc: instance.id],
    select_merge: %{registered_profils: count(profils.id)

But to be honest I don’t know if this is the best way but it works. ^^

abdelaz3r

abdelaz3r

Ok, thanks a lot. It doesn’t work, but I think I undestand better :wink:

Now, the query looks like that:

query =
  from instance in Instance,
    left_join: factions in assoc(instance, :factions),
    left_join: registrations in assoc(factions, :registrations),
    preload: [factions: factions],
    select_merge: %{registrations_number: count(registrations.faction_id)},
    group_by: registrations.faction_id,
    order_by: [desc: instance.id]

And the real SQL query that ecto make is (after formatting):

SELECT
  i0."id",
  i0."game_data",
  i0."game_status",
  i0."metadata",
  i0."name",
  i0."opening_date",
  i0."status",
  i0."inserted_at",
  i0."updated_at",
  count(r2."faction_id"),
  f1."id",
  f1."capacity",
  f1."faction_ref",
  f1."instance_id",
  f1."inserted_at",
  f1."updated_at"
FROM "instances" AS i0
LEFT OUTER JOIN "factions" AS f1 ON f1."instance_id" = i0."id"
LEFT OUTER JOIN "registrations" AS r2 ON r2."faction_id" = f1."id"
WHERE ((i0."status" > 1))
GROUP BY r2."faction_id"
ORDER BY i0."id" DESC
LIMIT $1 OFFSET $2 [25, 0]

Note: I have plugins for custom filter and pagination, so the limit and the where clause come from that.

And I have this error : (Postgrex.Error) ERROR 42803 (grouping_error) column "i0.id" must appear in the GROUP BY clause or be used in an aggregate function.

I’m not sure if it’s the query that is not correct or if I need some subqueries to achieve that.

Note2: I changed a bit the schema since my first post. Instead of having a many_to_many relation between Factions and Profils, I created a real schema “registration” that belong_to Factions and Profils (I need to store other informations into registration).

abdelaz3r

abdelaz3r

Yep ok, but the thing is, you don’t load data from section, you only filter category by the section_id. I’m trying to list all sections (in your situation), with their corresponding categories AND the count of ads. Which is why Postegres is not very happy.

But thanks again for the help :wink:

I’m now looking on this topic : Ecto subqueries with virtual fields? - #9 by xadhoom which may help me eventually.

Last Post!

Kurisu

Kurisu

Ok in fact I also did that…
Here is my code:

  def list_sections do
    Section
    |> order_by([:weight])
    |> Repo.all()
  end

  # preload active ads count per category
  def list_sections(:ads_count) do
    preload_query = from c in Category,
      left_join: a in assoc(c, :ads),
      where: a.status == ^:active,
      or_where: is_nil(a.id),
      group_by: c.id,
      order_by: [c.weight, c.name],
      select_merge: %{ads_count: count(a.id)}

    list_sections() |> Repo.preload(categories: preload_query)
  end

But this means making 2 requests on the database.

Where Next?

Popular in Questions Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New

Other popular topics Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31586 112
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New

We're in Beta

About us Mission Statement