Loading filtered relation with Dataloader

I have three models, which are: professors, users and reviews.
In the model files, they are declared as

  schema "reviews" do
    ...
    belongs_to :user, ProfessorEscroto.Users.User
    belongs_to :professor, ProfessorEscroto.Professors.Professor
  end
  schema "professors" do
    ...
    has_many :reviews, ProfessorEscroto.Reviews.Review
    ...
  end
  schema "users" do
    ...
    has_many :reviews, ProfessorEscroto.Reviews.Review
  end

What I want to do is have an field on my Professor GraphQL schema, called myReview, which can get the review the user created to that professor. I could do it but it was making a SQL query for each professor in the response, so I wanted to load it with Dataloader, as I’m doing with every other field.

I could achieve this with the following field in my schema file:

 node object :professor do
    ...
    field :my_review, list_of(:review), resolve: dataloader(Datasource, :reviews, args: %{user: true})
  end

and this in my dataloader file:

  def data(current_user) do
    Dataloader.Ecto.new(Repo,
      query: &query/2,
      default_params: %{current_user: current_user}
    )
  end

  def query(Review, %{current_user: current_user, user: true}) do
    from(r in Review, where: r.user_id == ^current_user.id)
  end

…except that the response is an array. I tried to remove the list_of() from the field in the schema file and modify dataloader to

def query(Review, %{current_user: current_user, user: true}) do
    from(r in Review, where: r.user_id == ^current_user.id)
  end

but it won’t work in any way.

Does anybody have an idea on how to do this?

This is my repo btw, if it helps: https://github.com/CelsoBonutti/professor_escroto

Thank you very much!

Bear with me, I use dataloader on my app but it’s wrapped in a few helper functions, so I might be incorrect.

In any case, the dataloader library supports a tuple {:one, queryable or association} as its second argument, to return a single result (Repo.one) instead of a list (Repo.all)

I would try changing the resolve function of my_review to: dataloader(Datasource, {:one, :reviews}, args: %{user: true})

More details on https://hexdocs.pm/dataloader/1.0.7/Dataloader.Ecto.html

1 Like