guihig

guihig

Hi, i’m struggling to find a way to preload an association inside a embedded schema from the base schema level. Below is an example of what i’m trying to achieve:

defmodule TestAssoc do
  use Ecto.Schema

  schema "test_assoc" do
    field :name, :string
  end
end

defmodule TestEmbedded do
  use Ecto.Schema

  alias TestAssoc

  embedded_schema do
    belongs_to :test_assoc, TestAssoc
  end
end

defmodule Test.Repo do
  use Ecto.Repo,
    otp_app: :test,
    adapter: Ecto.Adapters.Postgres
end

defmodule Test do
  use Ecto.Schema

  alias TestEmbedded

  alias Test.Repo

  schema "test" do
    embeds_one :test_embedded, TestEmbedded
  end

  defp load_test do
    %Test{}
    |> Repo.all()
    |> Repo.preload({:test_embedded, [:test_assoc]})
  end
end

Is there any way to do this with embedded schemas?

Thanks in advance.

Showing Posts 1 to 7

al2o3cr

al2o3cr

This PR suggests it should definitely be possible to preload test_assoc on a single TestEmbedded struct:

https://github.com/elixir-ecto/ecto/pull/3368

In the case you’re looking for in load_test, I’d expect this might work:

%Test{}
|> Repo.all()
|> Repo.preload(test_embedded: :test_assoc)

In the same way you’d preload a has_one and an association on that record.

LostKobrakai

LostKobrakai

I’ve seen a few people ask for that in the last handful of weeks. I’m really curious about the usecase behind that. Embeds are not bound by foreign key constraints, so this feels like something bound to get out of consistency.

guihig

guihig OP

I’ve tried this method, but it throws the exception below:

** (ArgumentError) schema Test does not have association :test_embedded

LostKobrakai

LostKobrakai

Are you on a recent enough ecto version (granted I don’t know if that PR is already in a released version)?

guihig

guihig OP

I’m on ecto 3.5.5

  • ecto 3.5.5 (Hex package) (mix)
    locked at 3.5.5 (ecto) 98dd0e5e
    ok
guihig

guihig OP

At the moment I did a helper to do the recursive preload with fields that have embedded.
Is it okay to do this?

defmodule Test.Repo do
  use Ecto.Repo,
    otp_app: :test,
    adapter: Ecto.Adapters.Postgres

  def preload_with_embedded(struct_structs_or_nil, preloads, opts \\ [])

  def preload_with_embedded(structs, preloads, opts) when is_list(structs) do
    Enum.map(structs, fn struct ->
      struct |> preload_with_embedded(preloads, opts)
    end)
  end

  def preload_with_embedded(struct, preload, opts) when is_map(struct) and is_tuple(preload) do
    {field, nested_preloads} = preload

    struct_scope = Map.get(struct, field, nil)

    if Ecto.assoc_loaded?(struct_scope) do
      preload_with_embedded_handler(struct, field, nested_preloads, opts)
    else
      struct
      |> preload(field, opts)
      |> preload_with_embedded_handler(field, nested_preloads, opts)
    end
  end

  def preload_with_embedded(struct, preloads, _opts) when is_map(struct) and is_list(preloads) do
    Enum.reduce(preloads, struct, fn p, acc ->
      acc |> preload_with_embedded(p)
    end)
  end

  def preload_with_embedded(struct, preload, opts) when is_map(struct) and is_atom(preload) do
    struct |> preload(preload, opts)
  end

  defp preload_with_embedded_handler(struct, field, nested_preloads, opts) do
    case Map.get(struct, field, nil) do
      ss when is_nil(ss) ->
        nil

      ss when is_map(ss) ->
        Map.put(
          struct,
          field,
          preload_with_embedded(ss, nested_preloads, opts)
        )

      ss when is_list(ss) ->
        Map.put(
          struct,
          field,
          Enum.map(ss, fn nested_struct ->
            nested_struct |> preload_with_embedded(nested_preloads, opts)
          end)
        )

      _ ->
        nil
    end
  end
end
ityonemo

ityonemo

Here’s one use case: (I think) Using embedded schema ad a final staging check to validate egress data that is going to a 3rd party data consumer. Once you perform the validation, you shoot it off to the 3rd party api and never see it again.

— All posts loaded —

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
apz
I’m new to elixir and just tried to install the elixirLS extension for VScode(ium) and it is throwing some errors that I would like help ...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews