OTQL examples
This page provides examples of OTQL queries, based on simplified schemas. The objective is to be less technical and illustrate how works our language by different use cases.
Basic queries
To begin, we'll talk about fundamentals of the syntaxe language. How it works and what it's the excepted result for each query. It will give you additional informations about OTQL.
Schema example
For the following examples, we consider the runtime schema below:
type UserPoint {
id : ID!
activities : [UserActivity!]!
profiles : [UserProfile!]!
}
type UserActivity {
id : ID!
events : [UserEvent!]!
}
type UserEvent {
id : ID!
name : String
}
type UserProfile {
id : ID!
age : String
}If we want to represent a userpoint, it will be object tree. For illustrate it, we could considerate it like this :

The different steps of an OTQL query
Even if the syntaxe of an OTQL query is close to a SQL one, the execution isn't the same at all. We talk about object tree and not column. This main difference gets lots of consequences and one of them is how the query is executed.
Query resolution is a two phases process
Narrow queried object mentioned in
FROMby applying aWHEREclause on it or/and on any sub-object's fields
When WHERE clause is applied on sub-object's field, if at least one sub-object validates the condition then all parent objects validate it as well.

2. Return only desired objects & fields by listing them in SELECT clause

Finally the query returns :
As you can see, despite the WHERE clause on $transaction_confirmed events, the query returns $page_view events since SELECT is applied from UserPoint.
Same explanation with multiple userpoints
Narrow queried object mentioned in
FROMby applying aWHEREclause on it or/and on any sub-object's fields

2. Return only desired objects & fields by listing them in SELECT clause

SELECT only be apply in userpoint still in the list, after the WHERE filterHere the query returns :
In this example, the UserPoint id=3 was not picked in the WHERE clause since it doesn't have any $transaction_confirmed event attached to it.
Change the scope of your query
Use FROM to chose your execution context
As you could see, the WHERE can filter only object in defined by the FROM . It gives you the ability to start the query where you need, it defines the scope of the query resolution and where the other operators are executed.
If you want to pick only a specific event, you will have to change the context. The FROM allows you to do so.

Here the query returns :
However specifying a sub-object also limit the scope of the predicate. For example, use FROM UserEvent doesn't give you access to UserPoint fields (like profiles).
Another way to get specific fields values : use @filter in the SELECT part to only retrieve elements you need
You can also use @filter if you don't want to change the scope of your query but you need to get only specific elements. It is completely independent of the WHERE clause and the filter is applied after the WHERE clause execution.
The first step will be the same as the one mentionned previously (narrow queried object mentioned in FROM using the WHERE clause).

But during the second phase, the @filter will be apply on selected objects.

Thefore, only $page_view are returned by the query :
Get condition on different sub-object Tree
You can add multiple conditions in the WHERE clause using boolean operators.

Add a condition from another Object Tree
As previously demonstrated, it's quite easy to add conditions in sub-objects scope (FROM). However if you need to execute your query in a specific scope and apply condition from an other object, you will have to use JOIN.
Note: the join is automatically resolved by UserPoint, there is no need to provide join constraint.

WHERE clause 
WHERE 
By the way, it is also possible to directly make the JOIN in UserProfile to get the same result :
Scoring operator
This is the runtime schema for examples below
Use case : Count UserPoint who bought more than X€ of product of the IT category
Use case : Count UserPoint who bought in average more than X€ of product of the IT category
Use case : Count UserPoint who bought more than X€ of product of the IT or Book category
Date operators
This is the runtime schema for examples below
Use case: Select all UserPoint who are celebrating their birthday today and are between 18 and 28 years old (rolling years).
Be aware that now is evaluated at the start of the segment calculation, which may result in a discrepancy between the expected and actual values.
Use case: Select all UserPoint who are celebrating their birthday in the next 7 days and are between 18 and 28 years old (rolling years).
Filters
@filter can be quite hard to understand, so let's see some examples to clarify its usage.
This is the runtime schema for examples below
Use case: I want to retrieve, for each user, all URLs of type "newsarticle" and category "actu" that were browsed yesterday.
If I use the following query :
This query returns many empty events, making the result unusable. Although the events are filtered, I haven’t excluded UserPoint that don’t contain any events with the clause.
To fix this, I need to add a WHERE clause to ensure each UserPoint has at least one event which matches the clause.
Here, the result is an improvement over the previous one, displaying only the events with a url of a page with the type "newsarticle" and the category "actu".
Now, if we want to retrieve information from activities while still filtering the events, we need to refine the query further.
As you can see, some events may be empty because the filter is not applied at the activities level. This means the returned activities contain at least one events which matches the clause.
If you try applying the filter at a higher level, specifically at the activity level:
By removing the event filter, the query now returns all events from activities that contain at least one page that matches the clause, rather than only pages that match.
To fix this, the first solution is to add another @filter to exclude unnecessary elements from both activities and events.
This query filters out unnecessary elements from both events and activities, but it is quite lengthy and difficult to read.
The second solution is to apply an empty @filter at the activities level in addition to the events level one:
The empty filter removes any events that are directly empty from the activities.
The empty filter only removes empty sub-objects. If you add another field that contains data, the filter will not remove the events
Last updated
Was this helpful?