how-to for filtering by embedded resource count #211
Description
I spent a long time looking through docs and issues trying to find a native way to filter a query result based on the array_length
of an embedded resource.
This use case can't filter on the client because it requires pagination across thousands of results.
Based on PostgREST/postgrest#1075, seems like it's not possible yet.
I was trying a syntax like:
GET /parent?select=*,children(*)&limit=10&order=children->>length.desc
but this gives an error:
column parent.children does not exist
Eventually found this earlier issue PostgREST/postgrest#845 laying out a very similar use-case, and this solution by @ruslantalpa using a new index & view:
One way to do it would be (but i am not completely sure it's optimal)
first, do not expose the schema where your tables live, expose a schemaapi
where you have only view definitionsthen have the last function that you defined somewhere and a view like
create or replace view api.films as select id, name, data.film_count_nominations from data.films;then add a index like this
create index on data.films (data.film_count_nominations(data.films.*));hopefully this index will prevent running that count query on each request.
If the index trick does not work then change the definition of the
api.films
view to be a join between films and nominations so that you can calculate that count columnit would be ideal to have the index thing work and not rely on a join because for cases when you do not need to filter by that count, the view is a simple select from the source table and not a join.
...
this thing is off the top of my head so take it with the grain of salt, but the main idea is correct, you have to bring up the "child property" up to the level of the parent so that you can filter based on it as if it's a property of the parent
Another potential solution, by @begriffs, using an SQL function to solve a similar problem: PostgREST/postgrest#443 (comment)
Now about adding a full_name column to your table, I think you can do it without making a whole view. If you define a function with the right name and argument type then postgresql will let you use it as a computed column. For instance:
CREATE FUNCTION full_name(users) RETURNS varchar LANGUAGE sql STABLE AS $_$ SELECT $1.first_name || ' ' || $1.last_name $_$;Once this function exists the client can use it as if it were a column like this
GET /users?select=full_name,*In fact the fake column is eligible for sorting too:
GET /users?select=full_name,*&order=full_name