satom99

satom99

Paginating associations with Absinthe Relay connections

Most articles on Absinthe suggest the use of dataloader when dealing with associations.
The reason being it batches successive associations and handles them all within a single query.

This does indeed work fine for most cases, but certainly not when doing pagination.
That is because one would ideally want to limit and offset per-association, which in turn
means applying pagination on a per-join basis and is not possible really with regular joins.
A feasible solution could be doing lateral joins with paginated subqueries, but because of
obvious performance reasons and because it is not completely supported within ecto and
its adapters, I guess we can agree not to go that way and look for a different approach.

Therefore, I am wondering. Specially to those doing GraphQL in production, how do you
approach this issue and paginate your associations exactly? Much appreciated! :slight_smile:

Most Liked

satom99

satom99

That does work indeed but say you were doing a second connection within the games connection.
If you were to do all connections this way, you’d end up querying the database multiple times, once
per successive connection, and running into the so called N+1 problem. That’s why dataloader comes
in handy, because it batches the associations and turns them into a single query automagically. :slight_smile:

That’s why I was wondering if there was a solution really besides just doing separate queries…
If otherwise, I’d also be looking for a generic resolver that would work for all associations, so that
I wouldn’t have to care really about coding each of the resolvers manually. :thinking:

ctbucha

ctbucha

A work-around that is working for me is to use dataloader for all queries, but if the GraphQL request is using pagination arguments on the specific resource, then add the parent_id to the dataloader args so that dataloader knows that it should not batch the SQL queries together. E.g. something like this:

import Absinthe.Resolution.Helpers, only: [dataloader: 2]

object :user do
  field :id, non_null(:id)
  field :name, non_null(:string)
  field :items, list_of(non_null(:item)) do
    arg :page, :integer
    arg :per_page, :integer
    arg :sort_field, :item_sort_field
    arg :sort_order, :item_order
    arg :filter, :item_filter
    resolve dataloader(Items, fn %{id: id}, args, _ ->
      {:items, case args do
        %{page: page, per_page: per_page} when is_integer(page) and is_integer(per_page) ->
          Map.put(args, :user_id, id)
        _ -> args
      end}
    end)
  end
end

This solution still results in the N+1 problem for this specific resource while using pagination on this resource, but you can still leverage batching for other resources in the query that are not being paginated.

Where Next?

Popular in Questions Top

dotdotdotPaul
Okay, I’m having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I’m sure I’...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a > b) do {:ok, "a"} end if (a < b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Other popular topics Top

JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 43487 311
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement