Skip to main content

Optional traversals

Optional traversals in J1QL allow for the inclusion of related assets in query results, marked by wrapping a portion of the query with ({query_portion})?. This feature enables combining entities from graph traversals and applying additional constraints.

Optional traversal example:
Find User (that IS Person)?

In the above example, we search for User entities and optionally traverse an IS relationship to a Person entity. If the relationship exists, the related Person entities are added to the list of results.

Relationships can still be chained within an optional traversal:

The query below will return a list of Device entities owned by a Person that is a User and User assets that do not have an indirect relationship to the Device.

Find User (that IS Person that OWNS Device)?

Relationships that come after an optional traversal are processed on the combined results:

This query searches for Users or UserGroups that directly assigned an AccessPolicy granting admin permissions to certain resources, or via an AccessRole assigned to the User/UserGroup.

Find (User | UserGroup)
(that assigned AccessRole)?
that assigned AccessPolicy
that allows as permission *
where permission.admin=true
return TREE

Optional traversals can also be chained:

The combined results from each previous optional traversal will be used in the next optional traversal. The below query will find User assets, Person assets that have an IS relationship to the User and Device assets that are owned by Person and User assets from the previous optional traversal.

Find User
(that is Person)?
(that owns Device)?
Return User, Person, Device

The optional traversals can also be aliased:

This allows the union set of entities to be used when returning results and when applying constraints. The following query illustrates aliasing an optional traversal.

Find User
(that is Person)? as userOrPerson
that owns Device
Where = ''
Return userOrPerson, Device

Traversals performed within the ()? function as normal graph traversals, so WITH filters can still be applied to assist with narrowing results:

Find User with name = 'test'
(that is Person with email = '')? as userOrPerson
that owns Device
return userOrPerson, Device