Skip to main content

Custom Search Query

Target audience: Developers & Modelers

Available from: 3.10

Introduction

Sometimes, users will want to see slightly different data or data visualised in a different way than the default views. These default views, when you authenticate, show the instances (e.g. cases, processes and tasks) that you have permission on.

There is also an API with some default filters available to search work items (i.e. root case or process instances) or tasks with the filterId open, all, completed, and mine. However, sometimes there is no filter available which is giving you exactly what you would like to have.

In this case, Flowable offers you to create your own Elasticsearch query. In this howto, we'll show a basic example how such a custom query can be built.

There is also an advanced howto on indexing and search that covers advanced topics.

Creating an Own Query

Flowable has the capability to create your own queries, which is a powerful feature, and you should definitely check out the documentation on indexing to get a full overview of all additional possibilities with Flowable.

A simple example

note

This part is not in the above video

As an example, let's assume that we would like to search for all cases having a given case definition key which were started by a given user.

Looking at our index (it's always a good idea to do this, this can be done through Flowable Control by clicking on Indexes > Cases), we see for example the following structure:

{
"__flowableVersion": 8,
"caseDefinitionKey": "testCaseModel",
"caseDefinitionName": "Test Case Model",
"startUserId": "admin",
"startTime": "2021-02-21T14:46:53.322Z",
"id": "CAS-a3260edf-7453-11eb-9d47-1281fbfbc379",
"state": "active",
"involvedUsers": [
"admin"
],
"variables": [
{
"id": "VAR-a326d231-7453-11eb-9d47-1281fbfbc379",
"name": "initiator",
"type": "string",
"scopeId": "CAS-a3260edf-7453-11eb-9d47-1281fbfbc379",
"scopeType": "cmmn",
"scopeDefinitionId": "CAS-95dd54ea-7453-11eb-9d47-1281fbfbc379",
"scopeDefinitionKey": "testCaseModel",
"rawValue": "admin",
"textValue": "admin",
"textValueKeyword": "admin"
}
],
"caseDefinitionId": "CAS-95dd54ea-7453-11eb-9d47-1281fbfbc379",
"caseDefinitionCategory": "http://flowable.org/cmmn",
"identityLinks": [
{
"id": "IDL-a3276e72-7453-11eb-9d47-1281fbfbc379",
"type": "assignee",
"userId": "admin"
},
{
"id": "IDL-a3359f47-7453-11eb-9d47-1281fbfbc379",
"type": "participant",
"userId": "admin"
},
{
"id": "IDL-a3276e73-7453-11eb-9d47-1281fbfbc379",
"type": "owner",
"userId": "admin"
},
{
"id": "IDL-a32635f0-7453-11eb-9d47-1281fbfbc379",
"type": "starter",
"userId": "admin"
}
],
"tenantId": "default"
}

We can see that our indexed document will have a startUserId property and a caseDefinitionKey property. We can use these parts of the document to search for our cases. This can be easily achieved with the following Elasticsearch query:

{
"query": {
"bool": {
"must": [
{
"term": {
"startUserId": "admin"
}
},
{
"term": {
"caseDefinitionKey": "testCaseModel"
}
}
]
}
}
}

Of course, this query would only find the cases instances with definition testCaseModel which were started by admin. We can replace admin and testCaseModel with whatever we want to search for.

An example with nested queries

Let's assume now that we would also like to search for all case instances with a given assignee.

Looking once more at our index, we can see that our indexed document will not have a simple assignee property but that it will have a nested identityLinks array, and that one such identity link will correspond to the case assignee. We can use this part of the document to search for our cases. In this nested array, there must be an entry with the userId equal to our assignee we are searching for, and the type of the field to assignee. This can be easily achieved with the following Elasticsearch query:

{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "identityLinks",
"query": {
"bool": {
"must": [
{
"term": {
"identityLinks.type": "assignee"
}
},
{
"term": {
"identityLinks.userId": "admin"
}
}
]
}
}
}
}
]
}
}
}

Of course, this query would only find the cases with the assignee admin. We can replace admin with whatever we want to search for.

Using the Query in Flowable

Going against Elasticsearch gives you now a different document structure than what you might be used to from Flowable.

When you go to Elasticsearch without going to Flowable you are losing the out-of-the-box access control which is built into Flowable. To avoid that, Flowable provides the possibility to query with your custom queries.

To create your own query you need to create a Query model in Flowable Design. We can call the model Case by Assignee and give it the key caseByAssignee.

There are two query types, the first is Safe query handling security and permissions for you, while the Custom query allows you to use the full features from Elasticsearch.

This query will use the case-instances index, since we need to specify this as the Source index.

The field Query Parameters allows us to specify custom parameters a user can pass in. There we can add the parameter assignee as mandatory.

As Template content we can specify our query as a FreeMarker template with the attributes we have set:

<#ftl output_format="JSON">
{
"bool": {
"must": [
{
"nested": {
"path": "identityLinks",
"query": {
"bool": {
"must": [
{
"term": {
"identityLinks.type": "assignee"
}
},
{
"term": {
"identityLinks.userId": "${assignee?json_string}"
}
}
]
}
}
}
}
]
}
}

The userId is now ${assignee?json_string}, which is exactly the same name as we have specified as a parameter. We use ?json_string to ensure that it is not possible to escape the double quotes of the JSON string (e.g. by providing a double quote as search query).

The Template preview allows us to look at the query with the filled in value, as well as validate the Freemarker template and the JSON syntax. You won't see a preview until you fill out assignee, since this field is mandatory.

Once done, the query model looks like this:

Query Model in Design

To make it available you need to publish an app which includes the query model.

Once this is done, we can execute a REST request to use our query: /platform-api/search/query-case-instances/query/caseByAssignee?assignee=admin.

As a result, we should see all case instances with the assignee admin.

Further reading

This article has only shown a small part of the Elasticsearch integration. In addition to executing queries, it's also possible to extract variables, write your own content into the index, and enhance the output result. As a further resource, it's recommended to look into the Work Indexing documentation and the Advanced search How-To.