TypeDB Fundamentals Lecture Series: from Nov 16 to Jan 9

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

A Get query consists of a match and a get clauses, followed by optional modifiers.

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.

Example of a get clause reducing the number of results
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 modifier syntax
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).

Sort example
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.

Example
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 modifier syntax
limit <value>;

Use the limit keyword followed by a positive integer to limit the number of results (answers) returned.

Example
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.

Example
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.

Result example
"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.

Example
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.

Example
match
$f isa file, has size-kb $s;
get $f, $s;
sum $s;

Omitting the variable $f in the get clause of the above query will result in missing all duplicated values of $s from the aggregation. For more information, see the Number of results section.

Maximum

Use the max keyword to get the maximum value among the specified long or double values of the matched variable.

Example
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.

Example
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.

Example
match
$f isa file, has size-kb $s;
get $f, $s;
mean $s;

Median

Use the median keyword to get the median value among the specified long or double values of the matched variable.

Example
match
$f isa file, has size-kb $s;
get $f, $s;
median $s;

Standard deviation

Use the std keyword to get the standard deviation value among the specified long or double values of the matched variable.

Example
match
$f isa file, has size-kb $s;
get $f, $s;
std $s;

Examples

Simple Get query example

A simple Get query example:

Simple 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:

  1. permission relation ($pe) of $x and $y variables.

  2. $x is person entity that has an attribute $x-n with the type full-name.

  3. The value of $x-n should contain the substring Kevin.

  4. The $y is a access type relation of $o a role of object and $act as action.

  5. $act has an attribute $act-n with the type name.

  6. $o has an attribute $o-fp with the value path.

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:

Permutations example
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.

To try the get queries in that example, we need to load the schema and the dataset provided above into a TypeDB database first.

Provide Feedback