Filter documents
It's fantastic to be able to store thousands of documents, but all this would be a silly business if you couldn't filter through them, wouldn't it?
The filter object allow you to specify criterias for selecting documents. You can filter on:
Display database setup
This page assumes your database contains Book and Person collections and some documents in them:
type Person {
name: String!
authoredBooks: [Book]
}
type Book {
title: String!
genre: String
plot: String
rating: Float
author: Person
ratings: [Float]
}
mutation {
a1:add_Person(input: {
name: "George Orwell"
}) { _docID }
a2:add_Person(input: {
name: "William Golding"
}) { _docID }
a3:add_Person(input: {
name: "David Foster Wallace"
}) { _docID }
a4:add_Person(input: {
name: "Victor Hugo"
}) { _docID }
}
mutation {
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-3517d1eb-351b-5231-8387-870893ffb395"
}) {
_docID
title
}
b12:add_Book(input: {
title: "Down and Out in Paris and London",
genre: "Biography",
plot: "The adventures of a penniless British writer among the down-and-outs of two great cities.",
rating: 4.09,
_authorID: "bae-3517d1eb-351b-5231-8387-870893ffb395"
}) {
_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-78e9c7be-10b9-5673-bad2-da3341367d4b"
}) {
_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-b59928dc-fd05-5fb7-aea2-9b24af5ebcea"
}) {
_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-b59928dc-fd05-5fb7-aea2-9b24af5ebcea"
}) {
_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-c169e917-df52-5603-9224-39c1757f1b04"
}) {
_docID
title
}
}
Single fields
{
Book(filter: {
title: { _eq: "1984" }
}) {
title
genre
plot
}
}
{
"data": {
"Book": [
{
"genre": "Fiction",
"plot": "A masterpiece of rebellion and imprisonment where war is peace, freedom is slavery, and Big Brother is watching.",
"title": "1984"
}
]
}
}
{
Book(filter: {
plot: { _ilike: "%love%" }
}) {
title
genre
plot
}
}
{
"data": {
"Book": [
{
"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.",
"title": "Les Misérables"
}
]
}
}
To filter on a single field, use the syntax fieldName: { operator: Value }, where:
fieldName– Name of the collection field to compare against.operator– Comparison operator to use.Value– Value to compare against, of the same type offieldName.
You need to explicitly specify the _and operator in case of two filters on the same field, because JSON objects cannot contain duplicate fields:
filter: {
_and: [
{ rating: { _gte: 4 } },
{ rating: { _lte: 5 } }
]
}
filter: {
rating: { _gte: 4 },
rating: { _lte: 5 }
}
Multiple fields
Additional fields listed in the filter object are implicitly combined with an AND operator.
{
Book(filter: { # filters combined with AND by default
title: { _eq: "1984" },
genre: { _eq: "Fiction" }
}) {
title
genre
plot
}
}
{
"data": {
"Book": [
{
"genre": "Fiction",
"plot": "A masterpiece of rebellion and imprisonment where war is peace, freedom is slavery, and Big Brother is watching.",
"title": "1984"
}
]
}
}
To use other operators and nested comparisons, use the syntax
filter: {
operator: [ { fieldName: Value }, ... ],
...
}
operator– Comparison operator to use.fieldName– Name of the collection field to compare against.Value– Value to compare against, of the same type offieldName.
{
Book(
filter: {
_or: [
{ genre: { _eq: "Fiction" } },
{ _and: [
{ rating: { _geq: 4 } },
{ rating: { _leq: 5 } },
] },
]
}
) {
title
genre
rating
}
}
{
"data": {
"Book": [
{
"genre": "Fiction",
"rating": 3.7,
"title": "Lord of the Flies"
},
{
"genre": "Nonfiction",
"rating": 4.18,
"title": "Consider the Lobster and Other Essays"
},
{
"genre": "Fiction",
"rating": 4.25,
"title": "Infinite Jest"
},
{
"genre": "Biography",
"rating": 4.09,
"title": "Down and Out in Paris and London"
},
{
"genre": "Fiction",
"rating": 4.21,
"title": "Les Misérables"
},
{
"genre": "Fiction",
"rating": 4.2,
"title": "1984"
}
]
}
}
The conditional keywords _and and _or accept an array, whereas _not accepts an object.
{
Book(
filter: { _not: { genre: { _eq: "Fiction" } } }
) {
title
genre
}
}
{
"data": {
"Book": [
{
"genre": "Nonfiction",
"title": "Consider the Lobster and Other Essays"
},
{
"genre": "Biography",
"title": "Down and Out in Paris and London"
}
]
}
}
Relationship fields
Filters can access fields within nested objects, such as in relationships:
{
Book(filter: {
genre: { _eq: "Fiction" },
author: { name: { _eq: "George Orwell" } }
}) {
title
plot
}
}
{
"data": {
"Book": [
{
"plot": "A masterpiece of rebellion and imprisonment where war is peace, freedom is slavery, and Big Brother is watching.",
"title": "1984"
}
]
}
}
The syntax to filter over sub-objects has one more level of nesting in field names: relFieldName: { fieldName: { operator: Value } }, where:
relFieldName,fieldName– Name of the collection field to compare against.operator– Comparison operator to use.Value– Value to compare against, of the same type offieldName.
One-to-many relationships
When filtering over one-to-many relationships from the many side, a document is returned if at least one of the linked documents fulfills the conditions: not all documents need to match the conditions.
For example, when filtering over people that have authored books of genre Fiction, every person that has at least one fiction book among their authored books will be returned:
{
Person(filter: {
authoredBooks: { genre: { _eq: "Fiction" } }
}) {
name
}
}
{
"data": {
"Person": [
{
"name": "George Orwell"
},
{
"name": "William Golding"
},
{
"name": "David Foster Wallace"
},
{
"name": "Victor Hugo"
}
]
}
}
If the return fields include the sub-object you filter on, the same filter is not applied to the result unless otherwise specified. For example, when filtering over people who have authored Fiction books, the returned books will include books of any genre:
{
Person(filter: {
authoredBooks: { genre: { _eq: "Fiction" } }
}) {
name
authoredBooks {
title
genre
}
}
}
{
"data": {
"Person": [
{
"authoredBooks": [
{
"genre": "Biography",
"title": "Down and Out in Paris and London"
},
{
"genre": "Fiction",
"title": "1984"
}
],
"name": "George Orwell"
},
{
"authoredBooks": [
{
"genre": "Fiction",
"title": "Lord of the Flies"
}
],
"name": "William Golding"
},
{
"authoredBooks": [
{
"genre": "Nonfiction",
"title": "Consider the Lobster and Other Essays"
},
{
"genre": "Fiction",
"title": "Infinite Jest"
}
],
"name": "David Foster Wallace"
},
{
"authoredBooks": [
{
"genre": "Fiction",
"title": "Les Misérables"
}
],
"name": "Victor Hugo"
}
]
}
}
You can override this behavior by specifying a different filter on the sub-object in the result fields. When specified explicitly, root-level and sub-objects filters are evaluated indipendently: the root filter is applied first and the sub-object filter is applied on the given field, per each returned document.
{
Person(filter: { name: { _eq: "George Orwell" } }) {
name
authoredBooks(filter: { genre: { _eq: "Fiction" } } ) {
title
genre
}
}
}
{
"data": {
"Person": [
{
"authoredBooks": [
{
"genre": "Fiction",
"title": "1984"
}
],
"name": "George Orwell"
}
]
}
}
JSON fields
If a JSON field is indexed, queries can traverse the JSON structure and filter by its inner properties. For example, with the following setup, it is possible to filter on i.love:
type jsonBlob {
jsonField: JSON @index
}
mutation {
add_jsonBlob(input: {
jsonField: {
i: {
love: "eating my family and commas"
}
}
}) { jsonField }
}
{
jsonBlob(filter: {
jsonField: {
i: {
love: { _like: "%family%" }
}
}
}) { jsonField }
}
{
"data": {
"jsonBlob": [
{
"jsonField": {
"i": {
"love": "eating my family and commas"
}
}
}
]
}
}
It is possible to filter for a JSON field's inner properties, but it's not possible to return them.
{
jsonBlob {
jsonField {
i {
love
}
}
{
}
Renamed fields (aliases)
You can filter over renamed fields via the _alias key. Alias names cannot be used directly in the filter object.
{
Book(filter: { _alias: { bookTitle: { _eq: "1984" }}}) {
bookTitle: title
}
}
{
Book(filter: { bookTitle: { _eq: "1984" }}) {
bookTitle: title
}
}
List fields
The list operators _any, _none, _all evaluate a scalar operator on the elements of a list or JSON field and return a boolean. For example, _any: { _lt: 3.5 } evaluates to true if all the elements of the list are lower than 3.5. List operators yield false on empty lists, null values, or non-list fields.
{
Book(filter: {
ratings: { _all: { _geq: 3.9 } }
}) {
_docID
title
}
}
{
"data": {
"Book": [
{
"_docID": "bae-d056ef07-f21d-5c0b-885b-25c35f04dea8",
"title": "Les Misérables"
}
]
}
}
{
Book(filter: {
ratings: { _any: { _lt: 3.5 } }
}) {
_docID
title
}
}
{
"data": {
"Book": [
{
"_docID": "bae-40292ec1-ab26-5184-8d63-486392e53dc4",
"title": "Infinite Jest"
},
{
"_docID": "bae-fca338d5-6a73-5676-8ae7-701165bd4f03",
"title": "1984"
}
]
}
}
{
Book(filter: {
ratings: { _none: { _lt: 3.0 } }
}) {
_docID
title
}
}
{
"data": {
"Book": [
{
"_docID": "bae-40292ec1-ab26-5184-8d63-486392e53dc4",
"title": "Infinite Jest"
},
{
"_docID": "bae-d056ef07-f21d-5c0b-885b-25c35f04dea8",
"title": "Les Misérables"
}
]
}
}
Operators and types
Scalar operators
| Operator | Description |
|---|---|
_eq | Equal to |
_neq | Not Equal to |
_gt | Greater Than |
_geq | Greater or Equal to |
_lt | Less Than |
_leq | Less or Equal to |
_in | In list |
_nin | Not In list |
_like | Like sub-string (supports % wildcard) |
_ilike | Case-Insensitive Like sub-string (supports % wildcard) |
_nlike | Not like sub-string (supports % wildcard) |
_nilike | Not like case-Insensitive sub-string (supports % wildcard) |
List operators
| Operator | Description |
|---|---|
_any | true if at least one element is true |
_none | true if none of the elements are true |
_all | true if all of the elements are true |
Operators supported by type
| Scalar Type | Operators |
|---|---|
| String, Blob | _eq, _neq, _like, _ilike, _nlike, _nilike, _in, _nin |
| Int, Float | _eq, _neq, _gt, _geq, _lt, _leq, _in, _nin |
| Boolean, ID | _eq, _neq, _in, _nin |
| DateTime | _eq, _neq, _gt, _geq, _lt, _leq, _in, _nin |
| JSON | _any, _all, _none, _eq, _neq, _like, _ilike, _nlike, _nilike, _in, _nin |
| List | _any, _all, _none, _eq, _neq |