PragTob

PragTob

:wave:

Relatively common setup:

I have a Thing which has_many SubThing. In the index view (showing many Things) I want to display a link or a text if there are any “sub things”. Otherwise not.

Of course I could just Repo.preload(:sub_things) but I don’t need them here so I wanna be light on the db/memory etc.

I know that I can write some query that returns me its own data structure telling me which Thing record has how many SubThings (or id any at all) and I could use that second data structure to display/not display them. I don’t have that query but I’m confident that I can write it with relative ease :smiley:

I think this is a relatively common problem, so the question is: “Is there a better/standard way to do this?” (my googling came up empty)

If I could wish for something then my Thing struct would have an additional attribute like:

%Thing{
  sub_things_exist?: true/false
  # or / and
  sub_things_count: 5
}

And I could get there with Repo.preload(:sub_things_exist?) or something similar.

Just to be clear I don’t want to introduce a counter cache (yet) it’s fine if it’s still queried from the database dynamically but ideally in one big query (this is on an index page with a lot of elements).

Thanks and cheers as always! :green_heart:

Showing Posts 1 to 8

LostKobrakai

LostKobrakai

Add field :sub_thing_count, :integer, virtual: true to your schema of Thing and instead of Thing use the following for querying:

sub_query = from s in SubThing, select: map(s, [:id, :thing_id])
query = from t in Thing,
  join: s in subquery(sub_query), on: s.thing_id == t.id, 
  group_by: t.id
  select_merge: %{sub_thing_count: count(s.id)}

You could skip the subquery and then join the whole table. What is faster probably depends on the column size of the sub_thing table.

hauleth

hauleth

You do not need that subquery, if this is just association then:

query = from t in Thing,
  join: s in assoc(s, :sub_thing),
  group_by: t.id
  select_merge: %{sub_thing_count: count(s.id)}

Will work as expected (DB optimisers are good enough to not fetch whole entries.

PragTob

PragTob OP

Thanks a bunch everyone, haven’t tried it yet but looks like exactly what I need :dancer:

PragTob

PragTob OP

Hello everyone!

So indeed this works, it needs some minor tweaking though:

query = from t in Thing,
  left_join: s in assoc(t, :sub_thing),
  group_by: t.id,
  select_merge: %{sub_thing_count: count(s.id)}

(assoc from t, left_join so that we also get entries with 0 counts and a little comma mistake)

However, I overestimated my handle on SQL and ecto saying I’d be able to easily make it work in a true/false fashion :sweat_smile:

I don’t really need it right now but it’d be great to know as for large collections count can become quite expensive. So something like an EXISTS query or something - it seems the difficulty might be relating to Support where exists(subquery) as well as where left in subquery · Issue #1479 · elixir-ecto/ecto · GitHub and the discussions about how we can even have Repo.exists? Existence query in `Repo` · Issue #2454 · elixir-ecto/ecto · GitHub

I tried changing the select_merge to true, is_nil(s.id) but for one reason or another none of them worked (most often because in group_by you can only use aggregate functions).

If someone has a result so that we make just a cheaper query that then in the struct saves has_sub_things true/false I’d be very happy to know how that works :grin:

LostKobrakai

LostKobrakai

I’m not sure how it would work in ecto, but lateral joins would basically do what you’re thinking of:

SELECT thing.id, sub_thing.available IS NOT NULL AS sub_thing_available 
FROM thing AS thing
LEFT JOIN LATERAL (
	SELECT true AS available 
	FROM sub_thing
	WHERE thing_id = thing.id
	LIMIT 1
) AS sub_thing ON true
LostKobrakai

LostKobrakai

count(s.id) > 0 would give you a boolean, if you want to stick to what you have right now.

hauleth

hauleth

“Hack” with count could be slow thought. I think that right now the best thing you can do is to use fragments, at least until Elixir will be able to do existential queries.

baljeet-aulakh

baljeet-aulakh

fragment for time being I guess!

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
rahultumpala
Hello, I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New

Other Trending Topics Top

jeffyzooom
Hi all, I’ve been working on RustyCSV, a CSV parser and encoder for Elixir backed by Rust NIFs. Version 0.4.0 is now available. The goa...
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
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews