Skip to main content
Version: 1.0 (Latest)

Group results

The groupBy argument allows you to group results into buckets basing on the value of one or more fields. For example, books of different genre can be grouped together and separated from books of other genres.

Display database setup

To reproduce the example results from this page, your database needs the following setup.

Database schema
type Book {
title: String!
genre: String
plot: String
rating: Float
ratings: [Float]
author: Person
seller: Company
}

type Person {
name: String!
authoredBooks: [Book]
}

type Company {
name: String!
sells: [Book]
}
Documents setup
mutation {
a1:add_Person(input: {
name: "George Orwell"
}) { _docID name }
a2:add_Person(input: {
name: "William Golding"
}) { _docID name }
a3:add_Person(input: {
name: "David Foster Wallace"
}) { _docID name }
a4:add_Person(input: {
name: "Victor Hugo"
}) { _docID name }

c1:add_Company(input: {
name: "The Independent Hipster Bookshop"
}) { _docID name }
c2:add_Company(input: {
name: "The World-Destroying Large Chain"
}) { _docID name }

b11:add_Book(input: {
title: "1984",
genre: "Fiction",
plot: "A masterpiece of rebellion and imprisonment where war is peace, freedom is slavery, and Big Brother is watching.",
rating: 4.20,
ratings: [3.8, 4.91, 3.1, 2.8],
_authorID: "bae-bc532931-4843-50bc-bbdd-3e31549c8cc6",
_sellerID: "bae-a5300933-fb0a-5b8f-b38e-202565993ff0"
}) { _docID title }
b12:add_Book(input: {
title: "Down and Out in Paris and London",
genre: "Memoir",
plot: "The adventures of a penniless British writer among the down-and-outs of two great cities.",
rating: 4.09,
_authorID: "bae-bc532931-4843-50bc-bbdd-3e31549c8cc6",
_sellerID: "bae-a5300933-fb0a-5b8f-b38e-202565993ff0"
}) { _docID title }
b21:add_Book(input: {
title: "Lord of the Flies",
genre: "Fiction",
plot: "At the dawn of the next world war, a plane crashes on an uncharted island, stranding a group of schoolboys.",
rating: 3.70,
_authorID: "bae-6025af65-e57e-5db5-84dd-d349b130c6d9",
_sellerID: "bae-a5300933-fb0a-5b8f-b38e-202565993ff0"
}) { _docID title }
b31:add_Book(input: {
title: "Infinite Jest",
genre: "Fiction",
plot: "A gargantuan, mind-altering tragi-comedy about the Pursuit of Happiness in America.",
rating: 4.25,
ratings: [3.1, 4.1, 4.5],
_authorID: "bae-26c791a7-fa81-5d86-95c5-4119e2fef915",
_sellerID: "bae-81d5fadb-c2a3-5d95-b235-a220c220bf79"
}) { _docID title }
b32:add_Book(input: {
title: "Consider the Lobster and Other Essays",
genre: "Nonfiction",
plot: "Do lobsters feel pain? Did Franz Kafka have a funny bone? What is John Updike's deal, anyway? And what happens when adult video starlets meet their fans in person? Essays that are also enthralling narrative adventures.",
rating: 4.18,
_authorID: "bae-26c791a7-fa81-5d86-95c5-4119e2fef915",
_sellerID: "bae-81d5fadb-c2a3-5d95-b235-a220c220bf79"
}) { _docID title }
b33:add_Book(input: {
title: "Girl with Curious Hair",
genre: "Fiction",
plot: "Remarkable and unsettling reimaginations of reality.",
rating: 3.85,
_authorID: "bae-26c791a7-fa81-5d86-95c5-4119e2fef915",
_sellerID: "bae-81d5fadb-c2a3-5d95-b235-a220c220bf79"
}) { _docID title }
b41:add_Book(input: {
title: "Les Misérables",
genre: "Fiction",
plot: "Victor Hugo's tale of injustice, heroism and love follows the fortunes of Jean Valjean, an escaped convict determined to put his criminal past behind him.",
rating: 4.21,
ratings: [3.9, 4.1],
_authorID: "bae-4bfe5f4c-d668-5dc3-9de2-eb598af3da7d",
_sellerID: "bae-81d5fadb-c2a3-5d95-b235-a220c220bf79"
}) { _docID title }
}

Syntax

Queries with groupBy have an optional GROUP sub-object among its return fields. It supports all arguments of query blocks and its return set gives access to all of the document's fields.

Syntax
TYPE(groupBy: [field]) {
field
GROUP(filter: Object, docID: [ID], order: [Object], limit: Int, offset: Int, groupBy: [fieldObj]) {
field
}
}
Allowed return fields

The return object can only include the grouped-by fields, the GROUP sub-object, and the result of other aggregating functions. For example, in a query with groupBy: [genre, rating], genre and rating are the only fields that can be directly returned. Other fields can be accessed from the GROUP sub-object.

Group by a single field

Group books by genre
{
Book(groupBy: [genre]) {
genre
GROUP {
title
plot
author {
name
}
}
}
}
Result
{
"data": {
"Book": [
{
"GROUP": [
{
"author": {
"name": "George Orwell"
},
"plot": "A masterpiece of rebellion and imprisonment where war is peace, freedom is slavery, and Big Brother is watching.",
"title": "1984"
},
{
"author": {
"name": "William Golding"
},
"plot": "At the dawn of the next world war, a plane crashes on an uncharted island, stranding a group of schoolboys.",
"title": "Lord of the Flies"
},
{
"author": {
"name": "David Foster Wallace"
},
"plot": "A gargantuan, mind-altering tragi-comedy about the Pursuit of Happiness in America.",
"title": "Infinite Jest"
},
{
"author": {
"name": "David Foster Wallace"
},
"plot": "Remarkable and unsettling reimaginations of reality.",
"title": "Girl with Curious Hair"
},
{
"author": {
"name": "Victor Hugo"
},
"plot": "Victor Hugo's tale of injustice, heroism and love follows the fortunes of Jean Valjean, an escaped convict determined to put his criminal past behind him.",
"title": "Les Misérables"
}
],
"genre": "Fiction"
},
{
"GROUP": [
{
"author": {
"name": "George Orwell"
},
"plot": "The adventures of a penniless British writer among the down-and-outs of two great cities.",
"title": "Down and Out in Paris and London"
}
],
"genre": "Memoir"
},
{
"GROUP": [
{
"author": {
"name": "David Foster Wallace"
},
"plot": "Do lobsters feel pain? Did Franz Kafka have a funny bone? What is John Updike's deal, anyway? And what happens when adult video starlets meet their fans in person? Essays that are also enthralling narrative adventures.",
"title": "Consider the Lobster and Other Essays"
}
],
"genre": "Nonfiction"
}
]
}
}
  • groupBy – Takes a list of field names.
  • GROUP – The aggregate sub-object contains all fields of the root object (Book), including relationships. Tweak the sub-object to further refine its output (see Combine root and GROUP query arguments).

Group by relationship

You can group results by a relationship fields as well. You can only group by the whole object; grouping by object sub-fields (i.e. groupBy: author.name ) is not supported.

Group books by author
{
Book(groupBy: [author], order: { author: { name: ASC } }) {
author {
name
}
GROUP {
title
plot
}
}
}
Result
{
"data": {
"Book": [
{
"GROUP": [
{
"plot": "A gargantuan, mind-altering tragi-comedy about the Pursuit of Happiness in America.",
"title": "Infinite Jest"
},
{
"plot": "Do lobsters feel pain? Did Franz Kafka have a funny bone? What is John Updike's deal, anyway? And what happens when adult video starlets meet their fans in person? Essays that are also enthralling narrative adventures.",
"title": "Consider the Lobster and Other Essays"
},
{
"plot": "Remarkable and unsettling reimaginations of reality.",
"title": "Girl with Curious Hair"
}
],
"author": {
"name": "David Foster Wallace"
}
},
{
"GROUP": [
{
"plot": "A masterpiece of rebellion and imprisonment where war is peace, freedom is slavery, and Big Brother is watching.",
"title": "1984"
},
{
"plot": "The adventures of a penniless British writer among the down-and-outs of two great cities.",
"title": "Down and Out in Paris and London"
}
],
"author": {
"name": "George Orwell"
}
},
{
"GROUP": [
{
"plot": "Victor Hugo's tale of injustice, heroism and love follows the fortunes of Jean Valjean, an escaped convict determined to put his criminal past behind him.",
"title": "Les Misérables"
}
],
"author": {
"name": "Victor Hugo"
}
},
{
"GROUP": [
{
"plot": "At the dawn of the next world war, a plane crashes on an uncharted island, stranding a group of schoolboys.",
"title": "Lord of the Flies"
}
],
"author": {
"name": "William Golding"
}
}
]
}
}

Group by multiple fields

To create groups basing on the value of multiple fields, you have two options:

  1. Provide the first field to the root groupBy argument and the second field to the groupBy argument in the GROUP sub-object. You get first-order groups basing on the first field, and nested groups basing on the second field. Continue to add fields for further nesting.
  2. Provide all fields as a list to the root groupBy argument. Each combination of groupBy fields values gives a separate group: the groups are not nested.
Option 1 – Groups by genre and author, nested
{
Book(groupBy: [genre]) {
genre
author { name }
GROUP(groupBy: [author]) {
author { name }
GROUP { title }
}
}
}
Result
{
"data": {
"Book": [
{
"GROUP": [
{
"GROUP": [
{
"title": "1984"
}
],
"author": {
"name": "George Orwell"
}
},
{
"GROUP": [
{
"title": "Lord of the Flies"
}
],
"author": {
"name": "William Golding"
}
},
{
"GROUP": [
{
"title": "Infinite Jest"
},
{
"title": "Girl with Curious Hair"
}
],
"author": {
"name": "David Foster Wallace"
}
},
{
"GROUP": [
{
"title": "Les Misérables"
}
],
"author": {
"name": "Victor Hugo"
}
}
],
"author": {
"name": "Victor Hugo"
},
"genre": "Fiction"
},
{
"GROUP": [
{
"GROUP": [
{
"title": "Down and Out in Paris and London"
}
],
"author": {
"name": "George Orwell"
}
}
],
"author": {
"name": "George Orwell"
},
"genre": "Memoir"
},
{
"GROUP": [
{
"GROUP": [
{
"title": "Consider the Lobster and Other Essays"
}
],
"author": {
"name": "David Foster Wallace"
}
}
],
"author": {
"name": "David Foster Wallace"
},
"genre": "Nonfiction"
}
]
}
}
Option 2 – Groups by genre and author, no nesting
{
Book(groupBy: [genre, author]) {
genre
author { name }
GROUP { title }
}
}
Result
{
"data": {
"Book": [
{
"GROUP": [
{
"title": "1984"
}
],
"author": {
"name": "George Orwell"
},
"genre": "Fiction"
},
{
"GROUP": [
{
"title": "Down and Out in Paris and London"
}
],
"author": {
"name": "George Orwell"
},
"genre": "Memoir"
},
{
"GROUP": [
{
"title": "Lord of the Flies"
}
],
"author": {
"name": "William Golding"
},
"genre": "Fiction"
},
{
"GROUP": [
{
"title": "Infinite Jest"
},
{
"title": "Girl with Curious Hair"
}
],
"author": {
"name": "David Foster Wallace"
},
"genre": "Fiction"
},
{
"GROUP": [
{
"title": "Consider the Lobster and Other Essays"
}
],
"author": {
"name": "David Foster Wallace"
},
"genre": "Nonfiction"
},
{
"GROUP": [
{
"title": "Les Misérables"
}
],
"author": {
"name": "Victor Hugo"
},
"genre": "Fiction"
}
]
}
}

Combine root and GROUP query arguments

You can specify filters and other query arguments both at the root level and in the GROUP aggregate. For example, you can query for books rated at least 4.2, group and sort them by genre, limit the group size to 3 and sort results within each group by book title:

Grouping with query arguments at root and group level
{
Book(groupBy: [genre], order: { genre: ASC }, filter: { rating: { _geq: 4.2 }}) {
genre
GROUP(limit: 3, order: { title: ASC }) {
title
}
}
}
Result
{
"data": {
"Book": [
{
"GROUP": [
{
"title": "1984"
},
{
"title": "Infinite Jest"
},
{
"title": "Les Misérables"
}
],
"genre": "Fiction"
}
]
}
}

The interplay between root and GROUP arguments can be subtle. When grouping results, the root object returns groups, and individual results are moved into the GROUP aggregate. For example, a limit argument at the root level affects the number of groups returned, not how many results get fed into the grouping:

Limit query to one group of unlimited size
{
Book(groupBy: [genre], limit: 1) {
genre
GROUP {
title
}
}
}
Result
{
"data": {
"Book": [
{
"GROUP": [
{
"title": "1984"
},
{
"title": "Lord of the Flies"
},
{
"title": "Infinite Jest"
},
{
"title": "Girl with Curious Hair"
},
{
"title": "Les Misérables"
}
],
"genre": "Fiction"
}
]
}
}
Limit groups size to one result only
{
Book(groupBy: [genre]) {
genre
GROUP(limit: 1) {
title
}
}
}
Result
{
"data": {
"Book": [
{
"GROUP": [
{
"title": "1984"
}
],
"genre": "Fiction"
},
{
"GROUP": [
{
"title": "Down and Out in Paris and London"
}
],
"genre": "Memoir"
},
{
"GROUP": [
{
"title": "Consider the Lobster and Other Essays"
}
],
"genre": "Nonfiction"
}
]
}
}

Filters at the GROUP level allow you to restrict the groups to get only some subset of results. However, combining filters at root and GROUP level can also be tricky business. If a root-level filter yields no records, there's no groups to be formed and the result set is empty. However, if a root-level filter yields enough records for a group to form, the group could still be present and empty if the GROUP-level filter further shrinks the result set.

Grouping with query arguments at root and group level
{
Book(
groupBy: [genre],
filter: {
rating: { _geq: 4 },
plot: { _ilike: "%love%" }
}
) {
genre
GROUP {
title
plot
}
}
}
Result
{
"data": {
"Book": [
{
"GROUP": [
{
"plot": "Victor Hugo's tale of injustice, heroism and love follows the fortunes of Jean Valjean, an escaped convict determined to put his criminal past behind him.",
"title": "Les Misérables"
}
],
"genre": "Fiction"
}
]
}
}
Grouping with query arguments at root and group level
{
Book(
groupBy: [genre],
filter: { rating: { _geq: 4 }}
) {
genre
GROUP(
filter: { plot: { _ilike: "%love%" }}
) {
title
plot
}
}
}
Result
{
"data": {
"Book": [
{
"GROUP": [
{
"plot": "Victor Hugo's tale of injustice, heroism and love follows the fortunes of Jean Valjean, an escaped convict determined to put his criminal past behind him.",
"title": "Les Misérables"
}
],
"genre": "Fiction"
},
{
"GROUP": [],
"genre": "Memoir"
},
{
"GROUP": [],
"genre": "Nonfiction"
}
]
}
}