Skip to main content

Advanced Query

In this section, we show you different advanced query capabilities.

Different query types in this section should be issued to different API endpoints. View the curl versions of the examples to see the proper endpoint for each query type.

Crawling the Graph

Subjects refer (join) to other subjects via any predicate that is of type ref. Every ref predicate relationship can be traversed, and can be done so in both directions -- forward and reverse.

For a forward traversal example, note our predicate chat/person which is of type ref and refers to a person subject. When we select * from chat, the results that return only show us the subject id from chat/person, they don't automatically crawl the graph to get more information about the person.

In order to also include the person details, we add to our select clause with a sub-query within our original query. This new query would look like:

{
"select": ["*", { "chat/person": ["*"] }],
"from": "chat"
}

In FlureeQL, this syntax is declarative and looks like the shape of the data you want returned. These sub-queries can continue to whatever depth of the graph you'd like, and for as many ref predicates as you like. Circular graph references are fine and are embraced.

Crawling the Graph, in Reverse

As mentioned, these relationships can also be traversed in reverse. If instead of listing the person for every chat, what if we wanted to find all chats for a person? Instead of selecting from chat, lets select from person and follow the same chat/person predicate but in the reverse direction. This query looks like:

{
"select": ["*", { "chat/_person": ["*"] }],
"from": "person"
}

In FlureeQL and SPARQL, note the underscore _ that was added to chat/person, making it instead chat/_person. In GraphQL, note chat_Via_person.

This special syntax indicates the same relationship, but in reverse. You'll now see all people, with all their chat messages.

For fun, you can add another sub-query to follow the chat message back to the person. Even though in this case it is redundant, and circular, Fluree exists happily in this paradox:

{
"select": ["*", { "chat/_person": ["*", { "chat/person": ["*"] }] }],
"from": "person"
}

Sub-Selection Options

When issuing a FlureeQL query, you can specify granular options that only apply to certain predicates. To do this, you need to use sub-select options.

A basic select clause may look something like this: ["handle", "fullName"]. Sub-select options are specified when any of those predicate names are turned into a map with the predicate name as the key, and an array as the value. For example, to give "handle" sub-select options, it would look like: [ { "handle": [OPTIONS HERE] }, "fullName"].

You have already seen a similar pattern with ref predicates. For example in the FlureeQL statement: "select": ["*", {"chat/_person": ["*"]}]. The nested select, or sub-select, statement is {"chat/_person": ["*"]}.

Within a given select statement, there may be multiple nested select statements in the FlureeQL syntax. GraphQL, by design, is entirely comprised of nested statements.

In FlureeQL

There are several sub-select options you specify. Certain options, such as _recur are only relevant for refs. While other options, such as _limit are only relevant for multi predicates.

KeyDescription
_limitLimit (integer) of results to include. For multi predicates. By default, returns 100.
_offsetOffset (integer) number results to include. For multi predicates. By default, offset is 0.
_recurNumber of times (integer) to follow a relationship. See Recursion. For ref predicates.
_componentWhether to automatically crawl the graph for component entities. Overrides the top-level option. For ref predicates.
_asAn alternate name for the predicate that is being referenced.
_orderBySpecify either a predicate (make sure to use the same name as returned in the results), or a two-tuple, where the first item is either ASC or DESC and the second item is the predicate name, i.e. ["ASC", "person/handle"]. Ordering is done before taking the number of results specified in limit.
_compactReturns all predicate names in their compact (non-namespaced format). For example, rather than return person/handle, would just return handle.

For example, you can issue the following query:

{
"select": ["handle", "fullName"],
"from": "person"
}

However, if you want to return fullName as name, you can issue the following query:

{
"select": ["handle", { "fullName": [{ "_as": "name" }] }],
"from": "person"
}

If you have a ref predicate, you can include any relevant sub-select options directly in the array where you specified any predicates you wanted to include:

{
"select": [
"handle",
{ "comment/_person": ["*", { "_as": "comment", "_limit": 1 }] }
],
"from": "person"
}

You can also sort each comment by comment/message.

{
"select": [
"handle",
{
"comment/_person": [
"*",
{ "_as": "comment", "_orderBy": "comment/message", "_limit": 1 }
]
}
],
"from": "person"
}

In GraphQL

Simply list the options inside of parentheses immediately after the chosen predicate. For example, we can limit the chat_Via_person predicates to only show 10 chats (in GraphQL, reverse references use Via rather than /_).

Note that in GraphQL, the options do not have a leading underscore. In GraphQL, the options that you can include are:

KeyDescription
limitLimit (integer) of results to include. Only for multi and ref predicates.
recurNumber of times (integer) to follow a relationship. See Recursion. Only for ref predicates.
asAlternate name for a predicate. Only for ref predicates.
{
graph {
person {
_id
handle
chat_Via_person(limit: 10) {
instant
message
comments {
message
}
}
}
}
}

Recursion

Recur is a sub-select option, which uses recursion to follow ref predicates that reference another subject in the same collection. For example, in the Basic Schema, we have a predicate, person/follows, which is a ref that points to another person.

Normally, if we want to query who a person follows, we would submit this query.

{
"select": ["handle", { "person/follows": ["handle"] }],
"from": "person"
}

However, if you want to keep following the person/follows relationship, we can specify the number of times we want to follow the given relationship in the following manner:

{
"select": ["handle", { "person/follows": ["handle", { "_recur": 10 }] }],
"from": "person"
}

The results will only return recursions for as long as their new information in a given recursion. For example, the result of the above query only returns a recursion that is two entities deep. This is because after we follow the person/follows relationship twice (in this given example), it will start returning the same information.

Multiple Queries

FlureeQL allows you to submit multiple queries at once by using the multi-query endpoint .

In order to do this, create unique names for your queries, and set those as the keys of the your JSON query. The values of the keys should be the queries themselves. If you are using GraphQL, you can simply nest your second, third, etc requests within the graph level of the request.

For example, this query selects all chats and people at once.

{
"chatQuery": {
"select": ["*"],
"from": "chat"
},
"personQuery": {
"select": ["*"],
"from": "person"
}
}

Any errors will be returned in a header, called X-Fdb-Errors. For example, incorrectCollection is attempting to query a collection that does not exist.

{
"incorrectCollection": {
"select": ["*"],
"from": "apples"
},
"personQuery": {
"select": ["*"],
"from": "person"
}
}

In FlureeQL, the response will have a status of 207, and it will only return the response for personQuery.

{
"personQuery": [
{
"_id": 4303557230594,
"person/handle": "zsmith",
"person/fullName": "Zach Smith",
"person/karma": 5
},
...
]
}