lorenzomar

lorenzomar

Ecto has_one sort association

Hi folks,

I have a sample application with User and Comments schemas with a relation 1:m between them.

I would like to add a 1:1 relation on User schema to retrieve last approved comment.

Do you know if there is some sort of preload_order option in has_one as we have in has_many relation?

Thanks in advance!!

First Post!

victorbjorklund

victorbjorklund

Yes, you can just do it the same way as for has_many.

So for a schema like this:

 schema "users" do
    field :email, :string
    field :password, :string, virtual: true, redact: true
    field :hashed_password, :string, redact: true
    field :confirmed_at, :naive_datetime
    has_many :comments, Comment
    has_one :latest_comment, Comment
    timestamps(type: :utc_datetime)
  end

You can achieve it like this:

latest_comments_query = from c in Comments, where: c.approved == true, order_by: [desc: c.inserted_at], limit: 1

Repo.all from u in User, preload: [latest_comment: ^latest_comments_query]

Most Liked

jerdew

jerdew

That sort of dynamic relationship isn’t how has_one is meant to work. You have to manually control a has_one such as: When you add a new comment, you would unset the current latest_comment and then set the new entry as the latest_comment.

What you’re thinking would take the shape of a virtual: true field, and you’d define a query like above. When you load the struct, you’d then run a separate query for the latest_comment, and populate the virtual field.

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Hey @lorenzomar the general challenge with this is when you are dealing with a collection of users and you want to get the most recent approved comment for each of them. This is doable with a lateral join, but at least last I looked Ecto won’t do this for you.

What will happen in the case of a has_one with a preload_order is that it will load ALL comments and then get the first one in memory. This is going to be a foot gun when you get more records.

Last Post!

fteschke

fteschke

From what I see in the Ecto debug log output, the standard preload query does not include a limit 1.
My guess: Because it is used both to preload for a single item and to preload for a list of items:

Repo.preload(comment, :latest_comment)
Repo.preload([comment_1, comment_2], :latest_comment)

For this reason, I think this suggestion is broken, as it selects only 1 comment overall, instead of one comment per user:

(Maybe it used to work, but the Ecto internals have since changed?)

Instead of a limit 1 it should be distinct on user_id:

latest_comments_query = from c in Comments, where: c.approved == true, order_by: [desc: c.inserted_at], distinct: c.user_id

Where Next?

Popular in Questions Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
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
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
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

Other popular topics Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
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
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
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

We're in Beta

About us Mission Statement