maz

maz

Ecto Query preloading complex association

I’m doing a fairly complex join where I want to preload an array of ContentMediaItems (called :contents) that are nested in an association, Channel

But it appears that ecto thinks I’m referencing the MediaItem in the preload even though I’m doing:

preload: [channel: {chan, contents: chancon}],

and name the associations previously:

join: chan in assoc(con, :channel),
join: chancon in assoc(chan, :contents),

So why does the exception

    ** (Ecto.QueryError) field `MyWord.Multimedia.MediaItem.channel` in preload is not an association in query:

appear?

Here is the full query along with the error below it.

    from(m in MediaItem,
      join: con in ContentMediaItems,
      on: m.id == con.media_item_id,
      where: is_nil(m.published_at) == false,
      join: chan in assoc(con, :channel),
      where: chan.id == con.channel_id,
      join: chancon in assoc(chan, :contents),
      on: chancon.channel_id == chan.id,
      join: org in Org,
      on: m.org_id == org.id,
      where: org.slug == ^org_slug,
      order_by: [{:desc, :published_at}],
      preload: [:mediaitemartifacts],
      preload: [channel: {chan, contents: chancon}],
      select: %{id: m.id, inserted_at: m.inserted_at, media_item: m, channel: chan}
    )

Exception:

** (Ecto.QueryError) field `MyWord.Multimedia.MediaItem.channel` in preload is not an association in query:

from m0 in MyWord.Multimedia.MediaItem,
  join: c1 in MyWord.Channels.ContentMediaItems,
  on: m0.id == c1.media_item_id,
  join: c2 in MyWord.Channels.Channel,
  on: c2.id == c1.channel_id,
  join: c3 in MyWord.Channels.ContentMediaItems,
  on: c3.channel_id == c2.id and c3.channel_id == c2.id,
  join: o4 in MyWord.Orgs.Org,
  on: m0.org_id == o4.id,
  where: is_nil(m0.published_at) == false,
  where: c2.id == c1.channel_id,
  where: o4.slug == ^"myword-app",
  order_by: [desc: m0.published_at],
  limit: ^41,
  select: %{id: m0.id, inserted_at: m0.inserted_at, media_item: m0, channel: c2},
  preload: [:mediaitemartifacts],
  preload: [channel: {c2, contents: c3}]

Relevant schema information:

schema "mediaitems" do
    has_many(:mediaitemartifacts, MyWord.Multimedia.MediaItemArtifact)
    many_to_many(:channels, Channel, join_through: "channels_content_media_items", unique: true)

schema "channels" do
  has_many(:contents, ContentMediaItems)

schema "channels_content_media_items" do
  belongs_to :channel, Channel
  belongs_to :media_item, MediaItem

Marked As Solved

jswanner

jswanner

When using assoc/3 or preload the name of the association given as an argument needs to match the name given in the schema (including pluralization).

In the case of your error message, I’m pretty sure you need to use :channels not :channel.

Also Liked

sodapopcan

sodapopcan

Chiming in to say: when preloading in the query with complex joins like that, it can often be very slow. This is because only one query is run which returns a massive, de-normalized table that has to filtered down by Elixir. I would try it out with Repo.preload as well to see if there is a difference. There might not be, but from experience I once had a response time go from over 30 seconds to under 1 second just by switching to Repo.preload. Fewer queries aren’t always better!

Last Post!

maz

maz

This is really good advice and is what I ended up doing.

So to help anyone who’s stuck with a similar problem, here is my less-heavyweight query(I only Ecto.preload :mediaitemartifacts at first).

    from(m in MediaItem,
      join: con in ContentMediaItems,
      on: m.id == con.media_item_id,
      where: is_nil(m.published_at) == false,
      join: chan in assoc(con, :channel),
      where: chan.id == con.channel_id,
      join: org in Org,
      on: m.org_id == org.id,
      where: org.slug == ^org_slug,
      order_by: [{:desc, :published_at}],
      preload: [:mediaitemartifacts],
      select: %{id: m.id, inserted_at: m.inserted_at, media_item: m, channel: chan}
    )

and later on, in the controller, I Repo.preload() the contents:

list =
    Enum.map(list, fn %{media_item: media_item, channel: channel} ->
        %{media_item: media_item, channel: Repo.preload(channel, :contents)}
    end)

Where Next?

Popular in Questions Top

ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

Other popular topics Top

jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31525 112
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42576 114
New

We're in Beta

About us Mission Statement