Advanced Filtering with GraphQL
To use this HowTo, first clone the Star Wars demo into your team on TerminusCMS. You will then have full access to the data needed for this tutorial.
TerminusDB exposes a filter object, which can be used to select specific documents. See here for basic Filtering
Now we can filter the homeworld of the people we are interested in. We will use a regex
because Tatooine is hard to
spell.
query{
People(filter: { homeworld: { label: { regex : "Tat.*" }}}){
label
homeworld{
label
}
}
}
You can also find out what fields are available with the same Ctrl-c
trick. Now, fire off the query above, and you'll see something like:
{
"data": {
"People": [
{
"label": "Luke Skywalker",
"homeworld": {
"label": "Tatooine"
}
},
{
"label": "Anakin Skywalker",
"homeworld": {
"label": "Tatooine"
}
},
{
"label": "C-3PO",
"homeworld": {
"label": "Tatooine"
}
},
{
"label": "Darth Vader",
"homeworld": {
"label": "Tatooine"
}
},
{
"label": "Shmi Skywalker",
"homeworld": {
"label": "Tatooine"
}
},
{
"label": "Owen Lars",
"homeworld": {
"label": "Tatooine"
}
},
{
"label": "Cliegg Lars",
"homeworld": {
"label": "Tatooine"
}
},
{
"label": "Beru Whitesun lars",
"homeworld": {
"label": "Tatooine"
}
},
{
"label": "R5-D4",
"homeworld": {
"label": "Tatooine"
}
},
{
"label": "Biggs Darklighter",
"homeworld": {
"label": "Tatooine"
}
}
]
}
}
Adding conjunctions
We can also add other elements to the filter, by using the _and
keyword. This requires that both filters are true.
query{
People(filter:{ _and : [ {homeworld : {label : {eq : "Coruscant"}}},
{species : {label : { eq: "Human"}}},
]}){
label
species{
label
}
homeworld{
label
}
}
}
Which yields:
{
"data": {
"People": [
{
"label": "Finis Valorum",
"species": {
"label": "Human"
},
"homeworld": {
"label": "Coruscant"
}
},
{
"label": "Jocasta Nu",
"species": {
"label": "Human"
},
"homeworld": {
"label": "Coruscant"
}
}
]
}
}
_not
and _or
You can also use _not
and _or
keywords to create even more complex
filters. To find all species, excluding droids with a lifespan greater
than 500 who don't have a typical sort of skin colour, you can write the following:
{
Species(
filter: {_and : [
{_not :{label:{eq:"Droid"}}},
{_or :[
{average_lifespan:{gt : "500"}},
{_not:
{skin_colors:
{anyOfTerms: ["blue", "black", "white", "green", "grey"
"brown", "red", "gray"]}}}]
}]}
) {
label
}
}
And yields:
{
"data": {
"Species": [
{
"label": "Yoda's species"
},
{
"label": "Pau'an"
},
{
"label": "Hutt"
},
{
"label": "Sullustan"
},
{
"label": "Cerean"
},
{
"label": "Iktotchi"
},
{
"label": "Tholothian"
}
]
}
}
A Bit of GraphQL theory
The filter is defined as part of the query for objects. If we look at
the People
query in the Star Wars demo we see the following:
type Query {
People(
id: ID
ids: [ID!]
"""skip N elements"""
offset: Int
"""limit results to N elements"""
limit: Int
filter: People_Filter
"""order by the given fields"""
orderBy: People_Ordering
): [People!]!
}
This query exposes a filter
argument, with the type of People_Filter
.
A People_Filter
in turn looks like:
input People_Filter {
birth_year: StringFilter
created: DateTimeFilter
desc: CollectionStringFilter
edited: DateTimeFilter
eye_color: StringFilter
film: Film_Collection_Filter
gender: StringFilter
hair_colors: StringFilter
height: StringFilter
homeworld: Planet_Filter
label: StringFilter
mass: StringFilter
skin_colors: StringFilter
species: Species_Filter
starship: Starship_Collection_Filter
url: StringFilter
vehicle: Vehicle_Collection_Filter
_and: [People_Filter!]
_or: [People_Filter!]
_not: People_Filter
}
In this way we can recursively qualify all of the objects to which a
People
might point to, terminating at leaves that use the various
concrete type filters.
For instance, the StringFilter
looks like:
input StringFilter {
eq: String
ne: String
lt: String
le: String
gt: String
ge: String
regex: String
startsWith: String
allOfTerms: [String!]
anyOfTerms: [String!]
}
We can specify any of these operands to narrow down our search. For more information on the operations against concrete datatypes, see the GraphQL Reference section.