Search code examples
graphqlgraphcool

GraphQL: Filter data in an array


I'm sure it's a simple thing to do, but I couldn't find anything in either GraphQL's doc or Graphcool's.

Say I have an entity with this schema (new GraphQL user, sorry if I make mistake in the schema representation):

Book {
  name: String!
  author: String!
  categories: [String!]
}

How would I do a query for all books that are part of the "mystery" category? I know I can filter with allBooks(filter: {}), but categories_in: ["mystery"] and categories_contains: "mystery" didn't do the trick.


Solution

  • Category model

    Thinking a bit more about this situation, creating a Category model is definitely the way to go.

    For example, imagine you want to allow readers to subscribe to their favorite categories later. Or, what if you want a list of all existing categories? Using string lists, you would need to query all books and somehow postprocess all obtained categories. Handling this on a model level rather than using string lists feels much more natural.

    Instead, you can create a new Category model and add a many-to-many relation between Category and Book. In situations like this, I like to add a unique enum field tag and a string field text. (A unique string field tag alone would also be suitable, probably a matter of taste.)

    With this setup, you can easily fulfill data requirements like

    Which books are assigned to a given category?

    query {
      # query books by unique category tag
      Category(tag: MYSTERY) {
        books {
          id
        }
      }
      # query books by specific category text
      Category(filter: {
        text: "mystery"
      }) {
        books {
          id
        }
      }
    }
    

    Which books are assigned to at least one category of a given list?

    query {
      allCategories(filter: {
        OR: [{
          tag: MYSTERY
        }, {
          tag: MAGIC
        }]
      }) {
        books {
          id
        }
      }
    }
    

    Which books are assigned to all categories of a given list?

    query {
      allCategories(filter: {
        AND: [{
          tag: MYSTERY
        }, {
          tag: MAGIC
        }]
      }) {
        books {
          id
        }
      }
    }
    

    Related filters

    Even though the above queries fulfill the specified data requirements, books are grouped by Category in the response, meaning that we would have to flatten the groups on the client.

    With so called related filters, we can turn that around to only obtain books based on conditions defined its related categories.

    For example, to query books assigned to at least one category of a given list:

    query {
      allBooks(filter: {
        OR: [{
          categories_some: {
            tag: MYSTERY
          },
          categories_some: {
            tag: MAGIC
          }
        }]
      }) {
        id
      }
    }