Counting Related Records with a Virtual Field in a Multi-Tenant app
In a multi-tenant application, when retrieving records from the database using a read action, is there a way to define a virtual field that counts the number of records in the database?
For example, something like:
34 Replies
yeah, use aggregates, they should respect the multitenancy stuff
From what I have read, aggregates operate on associations not over the resource itself
right, there was some Ash.count stuff I think
Elixir Programming Language Forum
How do I SELECT COUNT(*) w/o relationship?
I have a table with no relationship. I need to SELECT COUNT(*) FROM table WHERE condition; How do I do that inside an action/calculation/aggregate? Thanks.
at the bottom
Ash.count()
, pretty sure it takes tenancy into considerationThank you for sharing that post. I have saw it before and I just wondering if there is an alternative to don’t make another query or wrapped it in a transaction. Really appreciate your help @kernel
where do you want count to be? the way above is the only way to get it directly on the Resource iirc, otherwise you can have it on the 'Tenant' if you have a global tables tenant - there you should be able to do a
has_many :something, Something
, then an aggregates count :something_count, :something
, but yeah 🤷🏿♂️I’m using a schema-based approach for what it matters.
I think what you need to clarify is how you want to actually query this data
for example, if you had
:counter
as a calculation
would you really want results like this:
they'd all have the same valueIt looks silly but it’s a pattern that we currently use in my work. Maybe it’s not the pretties but there are some advantages using it in that way; like condense everything in one single query and also bringing the most up-to-date count.
The middle ground would be wrapped the two queries in a transaction.
I mean you could possibly have a custom calculation that calls Ash.count on that resource with the tenant or something
if you wanted that
so it would be in the same transaction
you won't get it into a single query though using the ash constructs imo
you still need to explain how you want to query the data, as theres at least 2 ways I can think of
are you wanting to query Thing from a single tenant, or are you wanting to return a list which shows all counts for all tenants or something
it doesn't make sense to have a global count on a single instance of a resource
For a single tenant...
Imagine that you have an User resource and you want to bring the records + its number of records. Something like Zach mentioned ☝️
This is a handmade approach
so wouldn't you have a user has_many educational_levels, and then do an aggregate count :educational_levels_count?
so you'd do Ash.all(User, load: [:educational_levels_count]) ?
or do you want each user to have a count(of all the other users in same tenant) attribute?
I'm using only one table. No associations are involved.
The name of the table is
educational_levels
I want to bring back the records for that table and the number of records on it.Right, but just to be clear, you'd be returning that for all rows
I'm going to use the following:
Yeap. I don't care if I have a 100 rows with the same info.
Gotcha, so I'm not sure if you actually have a good way to do that with Ash right now TBH
the primary reason being that there isn't a tool to reference the tenant's prefix
in the expression
actually, yeah, there is a way
Good point!
its just ugly
lol show me!
Maybe I can abstract it. = )
😆 probably not
You can make a relationship to "all of the educational levels"
To make a circular dependecy?
Circular dependencies aren't a problem with relationships
That's cool!
and then do
Let me try just for fun!
That wouldn't handle things like filters though
i.e
EducationalLevel |> Ash.Query.filter(active == true) |> Ash.Query.load(:count) |> Ash.read!()
would return active educational levels, with the total count of all educational levels, not just the active onesIt didn't work. I used this
And I got the following error:
:what:
you're on the latest versions of everything?
Does anything change if you do:
Nope. It didn't work as well. I just created the project a few days ago so I'm probably using the most up-to-date ash code. But I'm happy to check anything you think is necessary.
wild
Can you try adding a filter to the relationship?
That...also shouldn't matter though TBH.
what about as an aggregate
No luck. I'm using:
And I got:
On another note, your Ash Framework book has been a lifesaver. 🛟
Well then. Is this repo open source?
If you could open an issue on
ash_postgres
. I'll look into it sometime this week.
In the meantime, you can use the underlying tooling to workaround the issue
i.e write a generic action that calls into ecto
Maybe not that helpful if you aren't familiar with those tools thoughI'll make a repo with a simple setup during the week and let you know. I'll wait for your feedback until then. Generic is on my list of things that I need to learn but I'll pass for now. Thanks Zach!