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

ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
jc00ke
Expanding on this topic: https://forum.elixirforum.net/t/map-typespec-question/19217 Let’s say I have a map with required and optional k...
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
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New

Other popular topics Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30048 115
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers' Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New

We're in Beta

About us Mission Statement