Question about limit in Ecto, Absinthe and Dataloader

Hi!
I have a Category and Product relation.
Category has_many Products,
Products belongs_to Category.

I want to get all category and get 10 items for each category for my home screen.

in schema.ex

@desc "Get all categories"
field :categories, list_of(:category) do
  resolve(&Resolvers.Category.get_categories/3)
end

object :category do
  field :name, non_null(:string)
  field :products, list_of(:product) do
    arg :limit, type: :integer, default_value: 20
    resolve dataloader(Products, :products, arg: %{scope: :category})
end

in products.ex

def datasource() do
  Dataloader.Ecto.new(MyApp.Repo, query: &query/2)
end

def query(Product, %{scope: :category, limit: limit}) do
  Product
  |> where(active: true)
  |> limit(^limit)
end

def query(queryable, _) do
  queryable
end

in resolvers.category.ex

def get_categories(_, _, _) do
  {:ok, Category.get_categories()}
end

in category.ex

def get_categories() do
  Repo.all from c in Category
end

in graphiql query I tried

{
  categories {
    name
    products(limit: 10) {
      name
    }
  }
}

But it seems not working correctly.
it returns all categories but empty product and only one category returns 10 products
what am I doing wrong?

Maybe related to How to batch load with Absinthe Relay while supporting first: x and after_cursor?

1 Like

Yes I found this happens to me also

I am still looking for a solution, Do I have to raw query maybe?

I don’t know,
But I think raw query is more effective & easier to maintain,

I’ve faced issue similar to you, my solution use use group by & json_aggr, like below.

The performance is very good for me (74 ms), YMMV

The other good news that you can easily write this query in Ecto with the little help of fragment, so you can easily control the sort by, limit, selection fields of the subquery

To make it works with absinthe, you should simply call this query when resolving the list of your categories

Screen Shot 2020-02-20 at 11.42.14

The query in text

select 
  entry_taxon.taxon_id,
  count(*),
  (SELECT array_to_json(array_agg(row_to_json(t)))
    from (SELECT id, slug, title FROM entry e, entry_taxon et
	WHERE e.id = et.entry_id
	AND et.taxon_id = entry_taxon.taxon_id
    ORDER BY e.published_at
    LIMIT 10
    ) t)
FROM entry_taxon, entry
WHERE entry.id = entry_taxon.entry_id
GROUP BY entry_taxon.taxon_id