-
Hello! defmodule MyApp.Foo do
use Ecto.Schema
@derive {Flop.Schema, filterable: [], sortable: []}
schema "foo" do
field :period_start, :date
end
end In the MyApp.Foo
|> group_by([f], f.period_start)
|> select([f], %{
period_start: f.period_start,
ids: fragment("array_agg(?)", f.id)
})
|> MyApp.Repo.all() which returns the results in the following format:
When I try to do the same with the recommended MyApp.Foo
|> group_by([f], f.period_start)
|> select([f], %{
period_start: f.period_start,
ids: fragment("array_agg(?)", f.id)
})
|> Flop.validate_and_run(%{}) I get the following error:
I wasn't able to find any use case examples with |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 6 replies
-
Interesting, I haven't used You can get around this by passing a custom count query that does not include a count_query = distinct(MyApp.Foo, [f], f.period_start)
Flop.validate_and_run(Foo, params, for: Foo, count_query: count_query) Or if you need to to apply Flop filters: with {:ok, flop} <- Flop.validate(params, for: Foo) do
count_query = MyApp.Foo |> Flop.filter(flop, for: Foo) |> distinct([f], f.period_start)
{:ok, Flop.run(Foo, flop, for: Foo, count_query: count_query)}
end See also https://hexdocs.pm/flop/Flop.html#t:option/0 (I just noticed that the option is listed as The count is only queried for page and offset pagination types. For # force cursor-pagination and ignore page/page_size/offset/limit parameters
Flop.validate_and_run(Foo, params, for: Foo, pagination_types: [:first, :last]) |
Beta Was this translation helpful? Give feedback.
-
I see that Scrivener is detecting distinct and group_by usage and calling such queries as a subquery. This relies on internal Ecto details but I think it would be beneficial if something like that landed in Flop as well. I would suggest tiny changes compared to Scrivener's logic:
|
Beta Was this translation helpful? Give feedback.
-
I've ran into the same issues. So now I understand it's not supported, and only workarounds are possible. I have doubts about using the query without GROUP BY for counting - it's obviously a different query and not a proper solution.. For now I see the only clean workaround is to run all aggregations either with correlated subquery, or joined subquery, both via fragments. Yeah usually paginators run the same query as a subquery for counting, but it's not so simple with Ecto - I ran into an issue with return values: I also think Flop may need deeper understanding of the query, because filtering before and after aggregation is different (WHERE vs HAVING). A project using Flop may need both - so Flop has to undertstand which is which. Another option for Flop of course is just to give up - and direct users to fragments, or ignore aggregates in filters.. |
Beta Was this translation helpful? Give feedback.
-
So scrivener does what I described above (changing return values for the count query) |
Beta Was this translation helpful? Give feedback.
-
For someone who needs a good workaround in the meantime, this works: select: %{product: p, review_count: fragment("SELECT count(*) FROM reviews r WHERE r.product_id = ?", p.id)} It's called a correlated subquery and should have similar performance to joins and aggregation (at least in postgres). The advantage with this approach is that the main query remains un-aggregated and conflict free |
Beta Was this translation helpful? Give feedback.
Interesting, I haven't used
group by
clauses in combination with Flop before. The error is caused because by default, Flop takes the final query (minus pagination and order parameters) and runs a count query using Ecto.Repo.aggregate, which does not supportgroup by
.You can get around this by passing a custom count query that does not include a
group by
clause:Or if you need to to apply Flop filters: