How to hide results when the child is null in a Graphql Query

Let’s suppose that I have

{
   users {
     ...
     review {
       ...
     }
   }
}

Users might have or not a Review, Is there a way to hide a user in the results that does not have a review? I’m fetching the review using Dataloader. I don’t want a return like

{
   users: [
      {..., review: {...}},
      {..., review: {...}},
      {..., review: null},
      {..., review: null}
      ...
   ]
}

Hey @devmarco it sounds like you want to filter users by whether they have a review . If so, you should look at introducing an argument to the reviews field:

{
  users(withReviews: true) {
    ...
  }
}

If you never want to return users without reviews, then update your users resolver to always do the requisite join to filter out users without reviews.

1 Like

@benwilson512 I end up with this approach but the review is fetched using dataloader, so it receives the user object. and when I filter the users with something like

args
    |> filter_query
    |> Repo.all()


**Only users that have a review.** (Work)
{:with_review, true}, query ->
        from(q in query,
          join: r in assoc(q, :review),
          where: not is_nil(r)
        )

**Only users that do not have a review.** (Do not Work)
{:with_reviews, false}, query ->
        from(q in query,
          inner_join: r in Review,
          on: q.id != r.user_id,
          select: {q, r}
        )

Can you show some more code? Is that inside dataloader? If so, are you loading the users with dataloader?

Users are not loaded using dataloader just the review inside it.

def list_users(args \\ %{}) do
    args
    |> filter_query
    |> Repo.all()
  end

def get_review(_, %{id: id}, %{context: %{loader: loader}}) do
    loader
    |> Dataloader.load(Reviews, Reviews.Review, id)
    |> on_load(fn loader ->
      review = Dataloader.get(loader, Reviews, Reviews.Review, id)
      {:ok, review}
    end)
  end

query {
   users(withReviews: true/false) {
      review {
         ...
      }
   }
}

The filter_query function is the place that I’m trying to apply the query filters (Following the example in the book). So when I call list_users, it will goes through my filter function

defp filter_query(args) do
    Enum.reduce(args, User, fn
      {:filter, filter}, query ->
        query |> filter_with(filter)
    end)
  end

  defp filter_with(query, filter) do
    Enum.reduce(filter, query, fn
      {:with_review, true}, query ->
        from(q in query,
          join: r in assoc(q, :review),
          where: not is_nil(r)
        )

      {:with_review, false}, query ->
        from(q in query,
          join: r in assoc(q, :review),
          where: is_nil(r)
        )

      _, query ->
        query
    end)
  end

I want to find a way to return only users that do not have a review.

You need to left_join when with_review is false. In the :with_review, true clause you don’t need the here, a regular inner join will only include rows where the review is there anyway.

@benwilson512 you were right, thank you to help me on that.

from(
  q in query,
  left_join: r in assoc(q, :review),
  where: is_nil(r)
)

:+1: