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

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
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
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
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
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
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
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews