I'm trying to get join
to work using Ecto. Ecto seems to default to 'id' as the key field for join condition. Tried to change it to list_id and user_id using the foreign key settings in the schema, but it doesn't seem to work. What am I missing?
query =
from(i in SgListItems,
join: l in assoc(i, :sg_lists),
join: u in assoc(i, :sg_users),
select: [l.list_id, i.item_id]
)
is translated into
SELECT s1."list_id", s0."item_id" FROM "sg_list_items" AS s0 INNER JOIN "sg_lists" AS s1 ON **s1."id"** = s0."list_id" INNER JOIN "sg_users" AS s2 ON **s2."id"** = s0."author_id" ) []
The schema for sg_lists for instance is as follows:
@primary_key {:list_id, :binary_id, autogenerate: true}
schema "sg_lists" do
field(:list_title, :string, null: false)
field(:list_description, :map, null: false)
has_many(:sg_list_items, MyApp.SgListItems, foreign_key: :list_id)
timestamps()
end
Schema for sg_list_items below.
@primary_key {:item_id, :binary_id, autogenerate: true}
schema "sg_list_items" do
belongs_to(:sg_lists, MyApp.SgLists, foreign_key: :list_id, type: :binary_id)
field(:item_hierarchy, :map, null: false)
field(:item_title, :string, null: false)
field(:item_description, :map, null: false)
belongs_to(:sg_users, MyApp.SgUsers, foreign_key: :author_id, type: :binary_id)
timestamps()
end
You can explicitly set the field to join on, by using the :on
option of join
.
Try something like:
query =
from(i in SgListItems,
join: l in assoc(i, :sg_lists), on: [id: i.list_id],
join: u in assoc(i, :sg_users), on: [id: i.user_id],
select: [l.list_id, i.item_id]
)
On this line: [id: i.list_id]
, id
refers to :sg_lists
's id
, and on the next line, it refers to :sg_users
's one.
If you want to use different fields from :sg_list
or :sg_users
, you should put those instead of :id
, and replace i.list_id
for the correct field from SgListItems
This should work.
You can even add multiple conditions to the :on
option, something like:
on: [id: i.user_id, other_field: i.other_field]
would work as well. But I think what you need is just like in the snippet above.