Graphql-ruby pagination with limits generates n+1 queries

315 views Asked by At

Imagine that you have users and subscriptions on something. You need to make pagination for user's subscriptions. Each user has a different number of subscriptions. This is the first thing that came in my mind:

users = User.where(id:[array]).index_by(&:id) # find users and make an object with id as a key
subs = Subs.where(user_id: [array]).limit(3).offset(1) # find subs for all users what we need
subs.forEach{|s| users[s[:id]].subs <<  s} # build graphql response

But it won't work because it makes a limit for all users in general but we need for each of them. The output should be like this:

{
 users: [
  {
    id: 1,
    subs: [sub1, sub2] // this user has only two elements and it's like an end of pagination
  },
  {
    id: 2,
    subs: [sub3, sub4, sub5] // this user has more items on next page
  }
 ]
}

Graphql by default make sub-queries for each user to make it real but it n+1. Are there any ways to make it without n+1 and optimized by cpu and memory usage?

1

There are 1 answers

0
Alex Panfilkin On

Solved here https://elixirforum.com/t/how-to-do-pagination-in-a-nested-graphql-query-with-dataloader-batch-load/25282 maybe it helps somebody. It should be query like this with a partitioning.

  def query(queryable, params) do
   case params do
      %{chapters: true, offset: offset, first: first} ->
        last = offset + first
        query = from r in queryable, select: r, select_merge: %{chapter_number: fragment("row_number() over (PARTITION by parent_id order by \"name\")")}
        from r in subquery(query), select: %Wikisource.Book{id: r.id, name: r.name, info: r.info, preface: r.preface, info_html: r.info_html, preface_html: r.preface_html}, where: r.chapter_number >= ^offset and r.chapter_number < ^last
      %{order_by: order_by, offset: from, first: size} -> from record in queryable, order_by: ^order_by, offset: ^from, limit: ^size