I have this User schema and a UserRelationship schema that define a tutor-student relationship between users:
User
has_many :students UserRelationship, foreign_key: :instructor_id
has_many :instructors, UserRelationship, foreign_key: :student_id
UserRelationship
field :discipline, Ecto.Enum, values: [:maths, :science]
belongs_to :student, User, foreign_key: :student_id
belongs_to :instructor, User, foreign_key: :instructor_id
Now I want to query an user and get his/hers instructors, but It’d like the query to return a list of users in the instructors field, like so:
%User {
name: "John Doe",
instructors: [
%User{name: "Jane Doe"}, %User{name: "Another John"}
]
}
But as it is, if I just query for the user and preload the instructors field, I get a list of UserRelationship structs.
I’ve been playing with different ways to use preload and joins to achieve it, and I’m stuck.
It did however raised some questions.
This is the “closed” I got from an answer:
from(user in User,
where: user.username == ^username,
preload: [
instructors: ^from(relationship in UserRelationship
where: relationship.discipline == :maths,
select: relationship.instructor_id
]
|> Repo.one()
It returns a list of ID of the instructors, but:
-
If I try to use
relationship.instructoronselect:it gives me an error saying the field is a virtual field. I understand association fields are virtual, but why would this be an issue here? If I return justrelationshipon select, theinstructorfield will be available there (provided I preload it, of course), so why wouldn’t be available if I try to access it directly? -
If I preload
instructorand don’t use aselect:, everything works as expected (i.e. the field is preloaded and it returns all the rest of the query result with it). But if I keep thepreload:and add aselect:it gives me an error (even if I don’t reference the preloaded field):
(ArgumentError) you attempted to apply :__struct__ on <<182, 26, 243, 36, 249, 45, 70, 73, 178, 38, 184, 13, 194, 198, 141, 176>>. If you are using apply/3, make sure the module is an atom. If you are using the dot syntax, such as map.field or module.function(), make sure the left side of the dot is an atom or a map
I don’t understand this error, but it seems that just the fact you do a preload in a query if fundamentally changes the query structure?
- Finally, is there a way to apply
selecton preload fields?
I apologize this is huge. Haha ![]()
Thanks!






















