Nested preload from the doc makes me confused

Hello,

from p in Post, preload: [comments: :likes]`

from(p in Post,
  preload: [:comments, comments: :likes],
  select: p)

Are these queries identical (same number of SQL query) and do they return, both, all posts, their associated comments, and the associated likes for those comments?
Both queries come from the documentation of the Ecto.Query module v2.2.8.
Please, some explanations.

1 Like

If you don’t explicitly join the data you specified to be preloaded ecto will be preloading them in separate queries. Both those queries will preload comments and likes of comment, but I’d say the latter example does seem a bit redundant. I’m not even sure it’s valid, because for Ecto.Repo.preload mixing atom and keyword list notation does not work (the related docs update). So I’d avoid it just to not cause confusion.

1 Like

Yes. They’d be the same. Keep in my mind preloading that way without the joins will make more than 1 query to the database. You can rewrite it with joins to do it in one query.

query =  
  from p in Post,
  join: c in assoc(p, :comments),
  join: l in assoc(c, :likes),
  preload: [
    comments: {c, likes: l}
  ]

Repo.all(query)
1 Like

Keep in mind that a single query is not always optimal though, because of all the duplicate data you need to transfer over the wire with the joins :slight_smile:

1 Like

The later example is valid!

preload: [:comments, comments: :likes]

But this one is not:

preload: [comments: :likes, :comments]
** (SyntaxError) iex:6: syntax error before: comments

I found 2 other ways to achieve the same preload:

preload: [comments: :likes, comments: []]
preload: [comments: [likes: [] ], comments: []]

Courtesy of tkowal who shared a good article about Nested preload in Ecto and its “flexible” syntax.

Could you confirm these joins on Ecto.Schema are identical yours made on an association?

# elixir 1.6 formatter activated
query =
  from(
    p in Post,
    join: c in Comment,
    on: c.id == p.comments_id,
    join: l in Like,
    on: like.id == c.likes_id
)

Yep, I read your example with one user having different comments on a post, and how the user data is fetched for each comment!

BTW: I will “Consider replying to several posts at once” . Great forum, love it.