coen.bakker
Getting stuck on more complex Ecto queries: combining conditions, preloading and selecting
I am trying to get back all the stories that are authored or coauthored by a particular author. I also want to preload all the authors onto that author’s stories, because that author might not be the only author of their story. Additionally, I want to select certain fields from both the story structs and the preloaded authors.
My head is getting a bit dizzy trying to work this out, because I am new to complex Ecto queries, rather than straightforward/simple ones. I went over the Ecto documentation many times, but some the more advanced options I have only really read about, not used (successfully) or understood fully.
Some more code context.
I am starting with a user variable that satisfies: %User{} = user. In the code below authors are also users (N.B. in this case all users are authors and vice versa, while in other parts of the application, that is not true). (Edit: Also, an author can have many stories, and a story can have many authors. Joined through table :authors_stories).
I have tried many queries, but I always got the job only partly done. I have tried, for example:
user_id = user.id
query =
from u in User,
where: u.id == ^user_id,
join: s in assoc(u, :stories),
join: a in assoc(s, :authors),
select:
%{
id: s.id,
title: s.title,
authors: a
}
user_stories = Repo.all(query)
But this does not return all authors of a story per row. Preloading the authors onto the stories made sense to me, but I can’t seem to select only certain author fields when preloading. With the following code snippet I get all fields from authors.
user_with_preloads = Repo.preload(user, [stories: :authors])
user_stories = user_with_preloads.stories
The “preload queries” part of the documentation seemed maybe to be relevant, but was not able to make it work.
I would love to understand more complex querying, since it seems fundamental to me. So I am hoping to get some help tidying up some of the mess in my head around Ecto (and possible Elixir and SQL more generally). Any tips for this specific query and/or maybe books/blogs/courses, beyond the documentation, that are helpful to get a deeper understanding of the above?
Marked As Solved
coen.bakker
I got there.
user_id = user.id
author_query =
from u in User,
select: %{id: u.id, username: u.username, verified: u.verified}
query =
from s in Story,
join: a in assoc(s, :authors), on: a.id == ^user_id,
preload: [authors: ^author_query],
select: [:id, :title]
Repo.all(query)
I confused select: [s.id, s.title] with select: [:id, :title]. This is starting to make more sense now, since select: [:id, :title] returns a struct and select: [s.id, s.title] does not. Reckon Ecto relies on the struct to do its work preloading data.
Also Liked
jswanner
user_id = user.id
query =
from s in Story,
join: a in assoc(s, :authors), on: a.id == ^user_id,
preload: [:authors]
It’s usually easier to start your query with what you want returned and then figure out how to do the filtering: you want stories, so from s in Story. Rather than starting with how you are going to filter and then figuring out how to get what you want returned.
jswanner
I’m not sure, but my guess is it needs the struct in order to figure out what to preload.
What if instead of:
select: [s.id, s.title, s.authors]
You used:
select: struct(s, [:id, :title])
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









