-
-
Notifications
You must be signed in to change notification settings - Fork 158
feat: Support COUNT of relevant rows #94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Postgrest reports counts in the
range(
from: number,
to: number,
{
count,
foreignTable,
}: {
foreignTable?: string
count?: "exact" | "estimated" | "planned"
} = {},
): PostgrestTransformBuilder<T> {
const keyOffset =
typeof foreignTable === "undefined"
? "offset"
: `"${foreignTable}".offset`
const keyLimit =
typeof foreignTable === "undefined"
? "limit"
: `"${foreignTable}".limit`
this.url.searchParams.set(keyOffset, `${from}`)
// Range is inclusive, so add 1
this.url.searchParams.set(keyLimit, `${to - from + 1}`)
if (count) {
this.headers["Prefer"] = `count=${count}`
}
return this
} Then in the fetch promise could return this as part of the response: const contentRange = res.headers.get("Content-Range")
if (contentRange) {
const parts = contentRange.split(/[-\/]/)
// Note: this doesn't not handle responses like `0/*`
range = {
from: parseInt(parts[0], 10) + 1, // zero-based index
to: parseInt(parts[1], 10) + 1, // zero-based index
total: parseInt(parts[2], 10),
}
}
return {
range,
data,
status,
...etc
} This would involve modifying the response format |
Hey @stupidawesome! This issue is for getting just the I'd like to keep the library simple, so we don't plan to expose the HTTP response headers. |
Hi! First of all, thank you for creating such an amazing product. Supabase is what exactly I was looking for. Is this issue moving forward? I would like to have a count feature in Supabase. If it's pending right now, I was thinking I could tackle this issue. |
Thanks for hopping in @dshukertjr, this feature is long overdue... I'm starting to think that it might be worth modifying the response format, adding a There are two problems here:
The solution I'm thinking of is similar to how we now handle const { count } = await postgrest
.from('table')
.count('exact') // or 'planned', or 'estimated'. What should be the default here?
.gt('id', 10) And to get a count of the selected/modified rows (this is useful for our table editor pagination) we do: const { error, data, count } = await postgrest
.from('table')
.select()
.gt('id', 10)
.count('exact') I'm not sure if we need Would love to hear your thoughts @kiwicopple @steve-chavez @thorwebdev |
Just checking - the |
Yup, it just uses |
OK cool. IMO it seems redundant to add a whole function when it's still fetching the results from the database just for the headers. This one seems a natural extension of const { data, error, range, count } = supabase
.from('table')
.select('*', { count: 'exact' })
console.log(range) // [0, 24] (?)
console.log(count) // 1000 Does that work?
It's a good question. We're seeing a lot of people confused by our "row counts" in the dashboard becuase they are estimates on the tuples. Even though it's slower, I think the principle of least surprise applies here - we should use Once again this is breaking the PostgREST defaults, but we are seeing that people are coming in with small databases, then growing. In the time that it takes for them to grow their database, they can learn about performance optimizations like using wdyt? |
I like the extra Exact count is supported for insert/delete/update/rpc. And
The problem with that interface is that it doesn't specify the operation. It assumes count only works for GET. For HEAD, how about having an extra modifier that nulls the const { error, data, count } = await postgrest
.from('table')
.select()
.gt('id', 10)
.count('exact')
.head()
console.log(error, data, count) // null null 100 |
Actually scratch that, HEAD only makes sense for How about having // for select
const { data, error, count } = postgrest
.from('table')
.select('*', { head: true })
// for rpc
const {data, error, count} = postgrest
.rpc('get_status', { name_param: 'supabot' }, {head: true}) Both would null the data and error fields.
Agree with |
Makes sense, since we already have a bunch of
Didn't know you can do |
yeah |
Correct me if I am talking gibberish, but with this method, would you be able to query count value of joined table? For example, let's say you are developing a twitter clone, and you want to retrieve a users profile as well as the tweet count of the user to display them on a profile page. Something along the line of const { data, error } = await postgrest
.from('users')
.select(`
name,
tweets (
count(*) as count
)
`) I guess I would have to send two request to achieve this huh? One to get the user profile, and one to get the tweet count. |
Ignoring what I am saying about counts from foreign table, to summarize the discussion in this thread, it will look like this. Getting count along with table data: const { data, error, count } = await postgrest
.from('table')
.select('*')
.gt('id', 10)
.count() // 'exact' by default. 'estimate', 'planned' and null are also accepted Only getting the count: const { data, error, count } = await postgrest
.from('table')
.select('*', {head: true})
.gt('id', 10)
.count() // 'exact' by default. 'estimate', 'planned' and null are also accepted
console.log(data, error, count) // data and error are null. count contains row count. Do I understand it correctly? |
@dshukertjr No, this interface is just for counting the root table.
Not necessarily, you can always create a VIEW or FUNCTION that has the aggregate to do it in one request. There's also another option, that is currently undocumented in postgrest since it's not complete. Basically: const { data, error } = await postgrest
.from('users')
.select(`
name,
tweets (
count
)
`) That will get the tweets Calling other aggregate functions with |
Thanks @steve-chavez for pointing me to the right direction. Regarding this post, does this look like what everyone had in mind? I could try to write a pull request for this. |
That'd be awesome @dshukertjr! 👍 The only change is to make |
@dshukertjr Great! Go ahead! In case it helps, here's an example of joining both the const { data, error, count } = postgrest
.from('table')
.select('*', { head: true, count: 'exact' }) Also agree with soedirgo's idea about |
Thanks @soedirgo and @steve-chavez. I will add this feature and create a pull request. |
@steve-chavez I guess I am a bit confused with what the I do understand that it will turn |
@dshukertjr No, it would execute an HTTP HEAD request. See how a GET method is specified here. You'd have to change that to |
@steve-chavez Got it! Thank you! |
I may have a question regarding this. Having head and count as an option for select makes sense to me, but having those options for all the other methods listed do not make sense to me. Could you provide a simple example situation of when you would want to use |
@dshukertjr For RPC, there are set returning functions(return multiple rows) that can be called. A simple one: create function getallprojects() returns setof projects as $$
select * from test.projects;
$$ language sql; Using For POST(insert), you'd be interested in the For UPDATE/DELETE, the |
@steve-chavez Thanks for the clarification! I will start implementing |
@steve-chavez |
@soedirgo Yes. Now that you mention it,
@dshukertjr |
Okay, to summarize, it sounds like |
Closed by #147 🚀 |
Amazing job @dshukertjr 🚀 |
@kiwicopple |
https://supabase.com/docs/reference/javascript/select const { data, error, count } = await supabase
.from('cities')
.select('name', { count: 'exact' }) |
is there a way to use this with filtering? eg. only counting rows that have a specific user id |
should be fine. just tack on .eq("user_id",1) at the end |
Feature request
Is your feature request related to a problem? Please describe.
I'd like to perform
COUNT(*)
on relevant rows.Describe the solution you'd like
A
PostgrestTransformBuilder
method. PostgREST supports this.The text was updated successfully, but these errors were encountered: