Michael Forrest
Michael Forrest

Reputation: 3511

Using GraphQL structures to build complex database queries

I would like to specify inner constraints in a GraphQL query that would limit the results of the outermost query as part of a query / predicate builder I'm working on. I'm not sure if this is considered to be within GraphQL's capabilities but it makes sense to me as something that people would want to do.

For example, I might want to show a list of blog posts that were recently commented on like this:

{
  posts{
    title
    date
    comments(since: $earliestDate){
      body
      date
      author {
        name
      }
    }
  }
}

The normal behaviour of this would be to bring back all blog posts and only comments that met the criteria.

{
  "posts": [
    { 
      "title": "Post 1",
      "date": "2017-07-31"
      "comments": [
      ]
    },
    { 
      "title": "Post 2",
      "date": "2017-06-10",
      "comments": [
        {
          "body": "Comment text",
          "date": "2017-08-09",
          "author": {
             "name": "Michael"
          }
        }
      ]
    }

  ]
}

But I want my query to prevent the retrieval of "Post 1" because it has no comments in the last month, but I'm not sure that's something GraphQL will make easy to do.

Is there functionality within GraphQL to support returning this result?

{
  "posts": [
    { 
      "title": "Post 2",
      "date": "2017-06-10",
      "comments": [
        {
          "body": "Comment text",
          "date": "2017-08-09",
          "author": {
             "name": "Michael"
          }
        }
      ]
    }

  ]
}

Upvotes: 0

Views: 1131

Answers (1)

Ryan
Ryan

Reputation: 2998

TL;DR - In general, you want the behavior of a field to only be defined by:

  • The arguments passed to that field
  • The identity of the object that is being queried
  • The global context of the query (eg, the identity of the user executing the query)

I think that the behavior you're after is not really ideal for GraphQL. At least as I've seen, GraphQL tends to treat fields as relatively independent from each other (even though they're nested).

For example, you would not expect arguments passed to a child field to change the behavior of its parent. And similarly, I think you would not expect the presence or absence of a child field to change the behavior of its parent.

The best way to accomplish the behavior you're after would be to add an argument to the posts field, indicating that only posts with comments should be returned:

{
  posts(withCommentsOnly: true) {
    title
    date
    comments(since: $earliestDate) {
      body
      date
      author {
        name
      }
    }
  }
}

To understand the reasons why, just think about these kinds of scenarios:

{
  authors {
    id
    posts {
      comments { body }
    }
  }
}

If this query has the behavior you describe, for each author, you would only get the posts which also have comments. But then imagine that you re-query one of those authors later:

{
  node(id: "author_id") {
    ... on Author {
      posts { title }
    }
  }
}

Now would you get a different set of posts? That kind of behavior would make it very difficult for people to query your GraphQL schema using standard GraphQL clients, because client-side caching mechanisms would probably not be able to correctly update their caches.

Upvotes: 2

Related Questions