ashleyconnor

ashleyconnor

Selecting parent records based on state of latest child record

I have two schemas which look similar to the example below:

defmodule MyApp.Delivery do
  use Ecto.Schema

  schema "deliveries" do
    # Define your fields here
    has_many :delivery_statuses, MyApp.DeliveryStatus
    timestamps()
  end
end

defmodule MyApp.DeliveryStatus do
  use Ecto.Schema

  schema "delivery_status" do
    field :insert_date, :naive_datetime
    field :status, :string
    field :some_attribute, :string
    belongs_to :delivery, MyApp.Delivery
    timestamps()
  end
end

I’m attempting to write a queries:

  • Fetch a delivery by id and preload the latest status
  • Fetch a list of deliveries where the latest status matches a status parameter
  • Fetch a list of deliveries where the latest status is in a list or not in a list (give me all deliveries where status is A, B or C)

The first one I have working I believe:

# Define the subquery to get the latest status for each delivery
latest_statuses = from ds in MyApp.DeliveryStatus,
  select: %{delivery_id: ds.delivery_id, latest_date: max(ds.insert_date)},
  group_by: ds.delivery_id

# Define the main query to join with deliveries and filter based on the status of the latest status
query = from d in MyApp.Delivery,
  join: ds_max in subquery(latest_statuses), on: d.id == ds_max.delivery_id,
  join: ds in MyApp.DeliveryStatus, on: ds.delivery_id == ds_max.delivery_id and ds.insert_date == ds_max.latest_date,
  preload: [delivery_statuses: ds],
  select: {d, ds}

# Execute the query
result = MyApp.Repo.all(query)

However trying to filter by ds.status doesn’t work:

query = from d in MyApp.Delivery,
  join: ds_max in subquery(latest_statuses), on: d.id == ds_max.delivery_id,
  join: ds in MyApp.DeliveryStatus, on: ds.delivery_id == ds_max.delivery_id and ds.insert_date == ds_max.latest_date,
    where: ds.status == "desired_status",
  preload: [delivery_statuses: ds],
  select: {d, ds}

Rather than returning no results it returns the delivery with the DeliveryStatus that matches a parameter which is not always the latest one.

To summarize I am attempting to select objects based upon conditions in both the parent and child record but wish to return nothing if both conditions are not met.

Most Liked

ashleyconnor

ashleyconnor

Cool.

Looks like I can set that on a per schema basis or as a default across migrations:

 timestamps(type: :naive_datetime_usec)

OR

config :app, App.Repo, migration_timestamps: [type: :utc_datetime]
fuelen

fuelen

You probably have multiple delivery statuses on the same date. Try inserted_at instead of insert_date.

al2o3cr

al2o3cr

What about this alternative query:

latest_statuses = from ds in MyApp.DeliveryStatus,
  select: %{delivery_id: ds.delivery_id, delivery_status_id: ds.id},
  order_by: [desc: ds.insert_date],
  limit: 1

query = from d in MyApp.Delivery,
  join: ds_max in subquery(latest_statuses), on: d.id == ds_max.delivery_id,
  join: ds in MyApp.DeliveryStatus, on: ds.delivery_id == ds_max.delivery_status_id,
  where: ds.status == "desired_status",
  preload: [delivery_statuses: ds],
  select: {d, ds}

This will produce Delivery structs with only the “latest” DeliveryStatus loaded into delivery_statuses.

FWIW, if your application has a similar balance of reads vs writes on the status as “deliveries” - lots of reads, a small number of writes - it may be more efficient to cache some data on deliveries:

  • if filtering / showing delivery_status.status is the main thing, a latest_status column on deliveries would avoid the above subquery entirely.

  • if DeliveryStatus has many relevant fields, a back-referencing latest_delivery_status_id on deliveries would let ordinary join and preload clauses produce the same result

Where Next?

Popular in Questions Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
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
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
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
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
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
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
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
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list. ...
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

Other popular topics Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
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 41989 114
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
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
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New

We're in Beta

About us Mission Statement