Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

graphql: sort by nested field

Tags:

graphql

Let's say I have 2 tables:
- Users (id, name, post)
- Posts (id, message, user)

How can I fetch first 10 Posts order by User's name(desc)?

Here's how my schema looks like:

var PostType = new GraphQLObjectType({
  name: "Post",
  fields: () => ({
    id: { type: GraphQLInt },
    message: { type: GraphQLString },
    user: {
      type: UserType,
      args: {
        orderBy: { type: sortType }
      },
      resolve(parent, args) {
        console.info("Post resolve called.");
        return userMap[parent.user];
      }
    }
  })
});

var RootQuery = new GraphQLObjectType({
  name: "RootQueryType",
  fields: {
    allPosts: {
      type: new GraphQLList(PostType),
      resolve(parentValue, args) {
        console.info("allPosts resolve called.");
        return postData;
      }
    }
  }
});

And Query:

{
  allPosts {
    message
    user (orderBy: {field: "name", direction: ASC}) {
      name
    }
  }
}

Is there any way, I can call user resolver function before allPosts resolver function? Because, I am trying to fetch 10 users sorted by name and then pass post ids to allPosts resolver.

like image 951
Pankaj Vishwani Avatar asked Apr 04 '18 02:04

Pankaj Vishwani


People also ask

Does GraphQL support sorting?

You can sort GraphQL query results using an index and a user-defined function. The following example uses the following components: A GraphQL schema named schema.

How do you sort GraphQL results?

Results from your query can be sorted by using the order_by argument. The argument can be used to sort nested objects too. The sort order (ascending vs. descending) is set by specifying the asc or desc enum value for the column name in the order_by input object, e.g. {name: desc} .

How do you sort descending in GraphQL?

If you'd like to sort it in descending order, replace ASC with DESC .

Where is GraphQL?

GraphQL Query Filter - Where Clause You can filter the data returned by your queries with the where argument. The where argument is applied on a specific field and it filters the results based on that field's value. For example, you can use the where argument to fetch all the private todos.


1 Answers

GraphQL fields are resolved in a top-down fashion. That means allPosts is resolved first, then then message and user fields (simultaneously) and then the name field. This has to happen, as the "parent" or root field's resolved value determine's the value that's then passed to the resolver for its children fields as the root value. Information flows from "higher" resolvers to "lower" ones, but not the other way around.

Your orderBy argument here probably should be an argument on the allPosts field rather than the user field. There's two reasons to do that: (1) conceptually, regardless of the sort criteria, you are sorting the Posts returned by allPosts -- by convention, it just makes sense to put the sort there; (2) the argument is probably needed by the allPosts resolver more than it's needed by the user resolver.

To make the above work, you'll probably need to modify how you identify the sort criteria (making field a path like user.name for example). You may also need "lift" the logic for populating the users up into the allPosts resolver. For example:

resolve(parentValue, { sortBy: { path, direction } }) {
  const data = postData.map(post => {
    post.user = userMap[post.user]
    return post
  });
  // using lodash
  return orderBy(data, [(post) => get(post, path)], [direction])
}

It is possible to determine the selection set for other fields inside the request, including the arguments, by parsing the info object that's passed in as the fourth parameter to the resolver function. It's a pain though and I don't know if this particular case really justifies doing all that. You can read more about that approach in this answer.

like image 84
Daniel Rearden Avatar answered Sep 19 '22 01:09

Daniel Rearden