PragTob
![]()
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 ![]()
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! ![]()
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #blog-post
- #phoenix_html
- #iex
- #graphql
- #ai
- #genstage
- #elixirconf-us
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










Showing Posts 1 to 8- Show Best Posts
- Show All Posts (oldest first)
- Show All Posts (newest first)
LostKobrakai
Add
field :sub_thing_count, :integer, virtual: trueto your schema ofThingand instead ofThinguse the following for querying: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
You do not need that subquery, if this is just association then:
Will work as expected (DB optimisers are good enough to not fetch whole entries.
PragTob
Thanks a bunch everyone, haven’t tried it yet but looks like exactly what I need
PragTob
Hello everyone!
So indeed this works, it needs some minor tweaking though:
(assoc from t,
left_joinso 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
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
EXISTSquery 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 haveRepo.exists?Existence query in `Repo` · Issue #2454 · elixir-ecto/ecto · GitHubI tried changing the
select_mergeto true, is_nil(s.id) but for one reason or another none of them worked (most often because ingroup_byyou 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_thingstrue/false I’d be very happy to know how that worksLostKobrakai
I’m not sure how it would work in ecto, but lateral joins would basically do what you’re thinking of:
LostKobrakai
count(s.id) > 0would give you a boolean, if you want to stick to what you have right now.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
fragment for time being I guess!