Harrygr
Batch loading a field in absinthe with dataloader
I have an object in my Absinthe graphql schema that looks like this:
object :match do
field(:id, non_null(:id))
field(:opponent, non_null(:string))
@desc "The number of votes that have been cast so far."
field(:vote_count, non_null(:integer), resolve: &MatchResolver.get_vote_count/2)
# etc...
end
I’m using a resolver for vote_count that performs an ecto query using the parent match. This would run into the n+1 query problem however if a list of matches is queried. It currently looks like this:
def get_vote_count(_root, %{source: %Match{} = match}) do
count = match |> Ecto.assoc(:votes) |> Repo.aggregate(:count, :id)
{:ok, count}
end
I’m already using dataloader to batch load child entities but I’m can’t seem to get a custom run_batch function to work when using the Absinthe.Resolution.Helpers.dataloader function provided by Absinthe.
What’s the recommended approach for implementing custom batch queries using dataloader/ecto? Can someone give an example, including the schema definition part?
Most Liked
mbuhot
This github issue has an example of using a custom batch function to perform an aggregation.
The key is the %{batch: _, item: _} map passed to the dataloader helper, which I haven’t found documented anywhere except that issue ![]()
def run_batch(_, query, :post_count, users, repo_opts) do
user_ids = Enum.map(users, & &1.id)
default_count = 0
result =
query
|> where([p], p.user_id in ^user_ids)
|> group_by([p], p.user_id)
|> select([p], {p.user_id, count("*")})
|> Repo.all(repo_opts)
|> Map.new()
for %{id: id} <- users do
[Map.get(result, id, default_count)]
end
end
# Fallback to original run_batch
def run_batch(queryable, query, col, inputs, repo_opts) do
Dataloader.Ecto.run_batch(Repo, queryable, query, col, inputs, repo_opts)
end
Called from the GraphQL schema like:
field(:post_count, non_null(:integer) resolve dataloader(Posts, fn user, _args, _ ->
%{batch: {{:one, Post}, %{}}, item: [post_count: user]}
end)
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








