Why I get protocol Enumerable not implemented for #Ecto.Query?
Asked Answered
D

2

7

Although I am passing the query to repository inspired by this answer like this:

teams_users = Repo.all (from(t in Team, where: t.owner_id == ^user_id))
    |> Enum.each( &team_users/1 )


def team_users (team) do
    %{id: id} = team
    Repo.all (from(tu in TeamUser, where: tu.team_id == ^id))
end

However, I got this error:

[error] GenServer #PID<0.450.0> terminating
** (Protocol.UndefinedError) protocol Enumerable not implemented for #Ecto.Query<from t in App.Team, where: t.owner_id == ^1>
    (elixir) lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir) lib/enum.ex:116: Enumerable.reduce/3
    (elixir) lib/enum.ex:1477: Enum.reduce/3
    (elixir) lib/enum.ex:609: Enum.each/2
    (App) web/channels/user_channel.ex:93: App.UserChannel.handle_in/3
    (phoenix) lib/phoenix/channel/server.ex:223: Phoenix.Channel.Server.handle_info/2
    (stdlib) gen_server.erl:615: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:681: :gen_server.handle_msg/5
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3

What I am trying to do is to get all the teams, then get the users of each team, then I expect to have all the users in one array.

Do I miss something? any advice? is there a better way to achieve this?

Dorm answered 31/5, 2016 at 14:7 Comment(0)
I
8

So you have an issue here with this code:

teams_users = Repo.all (from(t in Team, where: t.owner_id == ^user_id))
|> Enum.each( &team_users/1 )

You should remove the space between Repo.all and (

teams_users = Repo.all(from(t in Team, where: t.owner_id == ^user_id))
|> Enum.each( &team_users/1 )

You could also write this as:

teams_users =
from(t in Team, where: t.owner_id == ^user_id)
|> Repo.all()
|> Enum.each( &team_users/1 )

However, doing this introduces an n + 1 query. You will make one query to fetch your teams, then another to fetch the team users. You should look into Repo.preload/2 for this.

teams_users =
  from(t in Team, where: t.owner_id == ^user_id)
  |> Repo.all()
  |> Repo.preload(:team_users)
Innerve answered 31/5, 2016 at 14:16 Comment(6)
But, how would I define the association :team_users in schema Team? I am using ecto 3.0-rc, and I already have a many to many table, but I didn't add any associations in my Team, User schemas..Dorm
hexdocs.pm/ecto/Ecto.Schema.html#has_many/3 and hexdocs.pm/ecto/Ecto.Schema.html#belongs_to/3 should help you out.Innerve
I can't add belongs_to to User as it has no table_id, I am using another table team_user to link Team and User which has user_id, team_id how would I define the many to many association?Dorm
There is an example of a has many through association in the docs I linked.Innerve
If you are using Ecto 2 then check out #35530220Innerve
Thanks, I will try to go with has many through, I am using Ecto 3Dorm
G
2

You are piping a query macro directly into Enum.each, instead of resolving the query with Repo.all and sending it into Enum.

Guyette answered 8/7, 2019 at 1:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.