Get query
A get query retrieves concepts from a TypeDB database that you can further process with the Driver API.
Get queries do not modify data, so they can be used in both read and write transactions. In read transactions, Get queries can use rule-based inference.
Behavior
A Get query projects concepts matched from a database to language-specific programmatic objects that can be used via Driver API methods.
A simple Get query returns a lazy stream/iterator of ConceptMap objects.
For every matched result, ConceptMap maps every query variable, mentioned in a get
clause,
to a concept matched from a database.
A concept can be either a type or an instance of a type.
A Get query with aggregation, grouping, or both has a different type of output. See the table in the Modifiers section.
Syntax
Get queries are written in TypeQL with the following syntax:
match <pattern>
get <variable> [, <variable>];
[sort <variable> [asc|desc];]
[offset <value>;]
[limit <value>;]
[group <variable>;]
[count; | (sum|max|min|mean|median|std) <variable>;]
Variables mentioned in a get
clause must be bound (set) in a match
clause of the same query.
Match clause
A match
clause is mandatory in a Get query.
You can use a declarative and composable TypeQL pattern in a match
clause and TypeDB will find data that matches
the pattern.
For more information on a match
clause, see the
Match clause description on the Queries page.
For more information on patterns used in a match
clause, see the
Pattern syntax section.
Get clause
A get
clause is used in a Get query to select variables (concept variables and value variables)
to include in every result of the output.
This clause is executed exactly once for every result matched by the preceding match
clause of the same query.
Unless aggregation or grouping is used, get
clause produces a ConceptMap for every matched result,
but deduplicates the results.
Following the get
keyword are one or multiple variables, separated by commas, and a semicolon at the end.
Every variable mentioned in a get
clause adds a respective mapping of the variable to a concept in every ConceptMap
of the output.
The get;
clause is used to get all variables mentioned in a match
clause pattern of a query.
ConceptMap
To get q ConceptMap simply iterate on lazy stream or iterator returned in a response to a Get query.
To retrieve a database concept from a ConceptMap, use Driver API ConceptMap.get(variable)
method,
that takes input of variable label and returns a Concept.
Further processing of a Concept is done via Driver API methods
Number of results
A Get query can return fewer results, than answers matched by its match
clause.
That is due to natural deduplication of results.
See an example below.
match
$p isa person, has full-name $n;
get $n;
In the above example match
clause matches all person
type instances that own a name
attribute.
The get
clause then returns those attributes.
What happens if two persons have the same name?
In TypeDB database that is stored, as two entities own the same attribute (instance of the name
attribute type).
The match
clause finds all pairs of a person entity and its owned attribute.
But get
clause returns only the attributes.
Since both persons own the very same attribute,
it will be returned only once, reducing the total number of results.
For more examples of filtering matched results, see the Permutations and Variables filtering.
Modifiers
There are multiple types of modifiers that can be used in a Get query to change its output:
Grouping modifier or aggregation functions can drastically change a query output, including its format. See the table below.
# | Query | Response format |
---|---|---|
1 |
Get query |
Stream/Iterator of ConceptMap |
2 |
Get query with aggregation |
Promise of Value |
3 |
Get query with grouping |
Stream/Iterator of ConceptMapGroup |
4 |
Get query with grouping and aggregation |
Stream/Iterator of ValueGroup |
Sort the results
sort <variable> [asc|desc] [,<variable> [asc|desc]];
Use the sort
keyword followed by a variable to sort the results.
A second argument is optional and determines the sorting order: asc
(ascending, by default) or desc
(descending).
match
$p isa person, has full-name $n;
get $n;
sort $n;
This query returns sorted full-name
attributes owned by person
entities.
To sort by multiple variables, add additional variables with a comma separator.
Offset the results
Use the offset
keyword followed by the number to offset the results.
This is commonly used with the limit
keyword to return a desired range of results for pagination.
Don’t forget to sort the results to ensure more deterministic and predictable results.
match
$p isa person, has full-name $n;
get $n;
sort $n;
offset 6;
limit 10;
The above example sorts the full-name
attributes of all person
entities in ascending order,
skips the first six results, and returns up to the next ten.
Limit the number of results
limit <value>;
Use the limit
keyword followed by a positive integer to limit the number of results (answers) returned.
match
$p isa person;
get $p;
limit 1;
The above example returns only one single (and random) instance of type person
.
We recommend using the limit
with the sorting aggregation
to get more deterministic and predictable results.
Grouping
We use the group
function, optionally followed by another aggregate function, to group the results by the
specified matched variable.
The output format is a lazy stream/iterator of ConceptMapGroup objects,
that have owner
and ConceptMaps
methods/fields.
match
$x isa person, has full-name $x-n;
$pe ($x, $y) isa permission;
$y (object: $o, action: $act) isa access;
$act has name $act-n;
$o has path $o-fp;
get $x-n, $act-n, $o-fp;
sort $o-fp;
limit 3;
group $o-fp;
The above example returns the full-name
attributes of all person
entities, the path
attributes of the object
entities
in any access
relations that are part of the permission
relation with the person
entities, and the name
attribute of the action
entity in those access
relations. The results are then sorted by the path
attribute in
ascending order, limited by only the first three results, and grouped by path
variable values.
The following or similar result can be obtained by running the query above without inference on the TypeDB server with the IAM schema and dataset from the Quickstart guide.
"LICENSE" isa path => {
{
$act-n "modify_file" isa name;
$x-n "Pearle Goodman" isa full-name;
$o-fp "LICENSE" isa path;
} {
$act-n "modify_file" isa name;
$x-n "Kevin Morrison" isa full-name;
$o-fp "LICENSE" isa path;
}
}
"README.md" isa path => {
{
$act-n "modify_file" isa name;
$x-n "Pearle Goodman" isa full-name;
$o-fp "README.md" isa path;
}
}
There can be a difference in the full-name
attribute returned for the README.md
path group because
the file with path README.md
is owned by multiple persons, and we are not sorting by the full-name
.
To avoid that, we need to sort not only by $o-fp
, but also by the $x-n
variable: sort $o-fp, $x-n;
Aggregation
Aggregation performs a calculation on a set of values and returns a single value.
TypeDB supports the following types of aggregation:
To perform aggregation in TypeDB, we add an aggregation function at the end of a Get query.
Aggregation function uses data returned by a preceding get
clause to perform aggregation
and return an aggregated result.
Count
Use the count keyword to get the total number of the results returned.
match
$o isa object, has path $fp;
get $o, $fp;
count;
The count
function counts the number of query results. See the Number of results section.
For a more complex example, see the Complex Get query example.
Sum
Use the sum
keyword to get the sum of the specified long
or double
values of the matched variable.
match
$f isa file, has size-kb $s;
get $f, $s;
sum $s;
Omitting the variable |
Maximum
Use the max
keyword to get the maximum value among the specified long
or double
values of the matched variable.
match
$f isa file, has size-kb $s;
get $f, $s;
max $s;
Minimum
Use the min
keyword to get the minimum value among the specified long
or double
values of the matched variable.
match
$f isa file, has size-kb $s;
get $f, $s;
min $s;
Mean
Use the mean
keyword to get the average value of the specified long
or double
values of the matched variable.
match
$f isa file, has size-kb $s;
get $f, $s;
mean $s;
Examples
Simple Get query example
A simple Get query example:
match
$p isa person,
has full-name "Kevin Morrison",
has email $e;
get $e;
The above query uses only two variables: $p
and $e
.
The full-name
attribute is not bound to a variable in this query.
The example above matches person ($p
) with ownership of the full-name
attribute with a value of Kevin Morrison
and
the email
attribute ($e
) with any value.
The get
clause then filters the results to retrieve only the email
($e
) attributes.
The response is a stream/iterator of ConceptMap.
Every ConceptMap bounds the variable $e
to an attribute of the email
type, that matches the pattern.
Complex Get query example
Let’s try a bit more complex pattern with some modifiers:
match
$pe ($x, $y) isa permission;
$x isa person, has full-name $x-n;
$x-n contains "Kevin";
$y (object: $o, action: $act) isa access;
$act has name $act-n;
$o has path $o-fp;
get $x-n, $act-n, $o-fp;
sort $o-fp;
group $o-fp;
count;
The example above uses a match
clause to find data that matches the following conditions:
-
permission
relation ($pe
) of$x
and$y
variables. -
$x
isperson
entity that has an attribute$x-n
with the typefull-name
. -
The value of
$x-n
should contain the substringKevin
. -
The
$y
is aaccess
type relation of$o
a role of object and$act
as action. -
$act
has an attribute$act-n
with the typename
. -
$o
has an attribute$o-fp
with the valuepath
.
The get
clause then filters the matched answers from the match
clause to get only the concepts for the
$x-n
, $act-n
, $o-fp
variables.
The results are sorted and grouped by the $o-fp
and aggregated with the count
function.
The response is the number of results for every $o-fp
: number of pairs $x-n
and $act-n
.
Permutations
If there are multiple variables returned in every result, then results of a query include all permutations of answers.
To illustrate that behavior, let’s
see what happens if we have three person
entities
and ten file
entities in a database with the IAM schema and
send the following get query:
match
$x isa person;
$f isa file;
get $x, $f;
How many results are we expecting to retrieve from a database?
Spoiler: 13 is the wrong answer here. |
As the example above doesn’t have any modifiers, aggregation, or grouping,
the number of results will depend on the number of matched solutions for the pattern in the match
clause.
So the TypeDB query processor will explore all possible solutions: each consisting of one person
entity
and one file
entity.
There are only 3 * 10 = 30
possible combinations of person
and file
entities, so we will get 30 results.
See the Patterns overview section of the Matching patterns page for more information.
Variables filtering
For the following example, consider the following database schema:
define
name sub attribute, value string;
age sub attribute, value long;
certified-fortune-teller sub attribute, value boolean;
person sub entity,
owns name,
owns age,
owns certified-fortune-teller;
Let’s explore the following query:
match
$p isa person,
has name `Bob`,
has age 31,
has certified-fortune-teller $cft;
get $p, $cft;
The above query will find every person
entity that has ownership over the instance of the attribute type name
with
the value of Bob
, ownership of the age
with the value of 31
, and the ownership of the certified-fortune-teller
attribute with any value.
With the get
clause, we filter the results to get the person
instances and the corresponding
certified-fortune-teller
attribute (represented by the $cft
variable in the pattern) for every matched result
in a database.
Why not filter for just the $cft
variable instead?
That can drastically alter the returned results as the returned results are deduplicated by design. See the Basic patterns page for more information on the number of results for pattern matching.
For example, let’s say we have ten people with the name Bob
and age 31
in our database.
Five of them have certified-fortune-teller
with the value false
, one has it as true
,
and the rest don’t have an ownership of the attribute.
See how to load such a dataset in a database
In TypeDB Studio, we can paste the following TypeQL in the text editor and send all the queries by a single click in a data/write mode. Make sure to commit the changes.
# These are the 5 instances of people with name Bob, age 31 and not cretified fortune tellers
insert $p isa person, has name "Bob", has age 31, has certified-fortune-teller false;
insert $p isa person, has name "Bob", has age 31, has certified-fortune-teller false;
insert $p isa person, has name "Bob", has age 31, has certified-fortune-teller false;
insert $p isa person, has name "Bob", has age 31, has certified-fortune-teller false;
insert $p isa person, has name "Bob", has name "Bobby", has age 31, has certified-fortune-teller false;
# This is the one and only instance of a person with name Bob, age 31 and a cretified fortune teller
insert $p isa person, has name "Bob", has age 31, has certified-fortune-teller true;
# These are the 4 instances of people with name Bob, age 31. No ownership of the boolean attribute
insert $p isa person, has name "Bob", has age 31;
insert $p isa person, has name "Bob", has name "Robert Jr.", has age 31;
insert $p isa person, has name "Bob", has age 31;
insert $p isa person, has name "Bob", has age 31;
# These are some random people, that doesn't meet pattern (Name: Bob and Age: 31)
insert $p isa person, has name "Bob", has age 20;
insert $p isa person, has name "Alex", has age 78, has certified-fortune-teller false;
insert $p isa person, has name "Alice", has age 31, has certified-fortune-teller true;
insert $p isa person;
To insert this dataset with any other client — make sure to send every line, except from comments, as a separate insert query.
For more information on an Insert query, see the Insert query page.
Those Bobs that don’t have the attribute ownership won’t be matched by the match
clause at all.
So we expect to get six results from the original Get query:
five person
instances owning the attribute with value false
and one with true
.
If we remove the $p
variable and use get $cft;
clause instead,
we’ll get only two results in response because we will only get
certified-fortune-teller
instances, and there are only two of those: an instance with the true
value and another
instance of the same type with the false
value.
The initial five instances of person
type all have ownership over the
same instance of the certified-fortune-teller
attribute type
with the value false
.
To get all the results, we add the person
type instances to the results because those are unique.
Even if some of them might have the exact same set of owned attributes, instances of the person
type are
different instances nonetheless.