Managing Data#
Introduction#
bpmn-server
relies on a Database to store workflow information.
This makes it suitable for long-running workflows and multi-servers.
Developers can query on data using Data Query
'bpmn-server' manages three collections in MongoDB:
wf_instances | stores workflow instances, including items, tokens, logs ,etc. |
wf_models | stores workflow models, this is important for querying on events |
wf_locks | to achieve concurrency, running instances place a lock in this collection |
api.data object provides several methods to handle workflow instances and items
While api.model object provides methods to access workflow models
In addition to saving bpmn specific properties, bpmn-server
supports the following data elements:
- Presistent Data
- instance.data
- item.vars
- In-Memory Data
- item.input
- item.output
All of the above all available during process execution and event listeners.
Instance Object#
The instance object is similar to:
{
"_id": {
"$oid": "66500c3ff0dedc85988cf6fa"
},
"version": 0,
"data": {
"caseId": 9787,
"starterUserId": "system",
"needsRepairs": "Yes",
"needsCleaning": "No"
},
"items": [
{
"id": "fd3d38fb-2eab-4ee4-a61e-0fe992f969c2",
"seq": 2,
"itemKey": null,
"tokenId": 0,
"elementId": "task_Buy",
"name": "Buy",
"status": "end",
"userName": "system",
"startedAt": { "$date": "2024-05-24T03:40:47.744Z" },
"endedAt": { "$date": "2024-05-24T03:43:48.045Z" },
"type": "bpmn:UserTask",
"timeDue": null,
"vars": {},
"instanceId": null,
"messageId": null,
"signalId": null,
"assignee": "system",
"candidateGroups": [ "Employee", "Manager" ],
"candidateUsers": [ "User1", "User2" ],
"dueDate": { "$date": "2024-05-29T03:40:47.746Z" },
"followUpDate": { "$date": "2023-10-31T00:00:00.000Z" },
"priority": "5"
},
],
"tokens": [/*Tokens Data */ ],
"loops": [],
"id": "0a081355-8050-45df-91db-8dd473b58bc0",
"name": "Buy Used Car",
"source": "/* ... bpmn in xml format */"
"savePoints": {/* SavePoints Data to restart at any point */}
"saved": {"$date": "2024-05-24T03:40:47.761Z" },
"endedAt": {"$date": "2024-05-24T03:44:01.463Z" },
"parentItemId": null
}
instance.data Scope#
The entire execution will have one data scope object, shared among all nodes, except the following will have own item part of the data object
- SubProcess
- and Loops (Multi-instances)
However, for SubProcess and Loop elements a seperate scope
Data Query#
The syntax follows MongoDB standards.
the query syntax must be
- instance attributes unqualified
- item attributes are qualified by items.\<attributeName\>
- data attributes are qualified by data.\<attributeName\>
Item Query#
example | will retrieve |
---|---|
{ "items.id": "value-of-id" } |
find items by id only - unique |
{ id: instanceId, "items.elementId": 'Approve' } |
find items by instance id and elementId |
{"data.caseId": caseId ,"items.elementId" : 'Request' } |
find items by caseId and item elementId |
{ "name" : "Leave Application" , "items.status": "wait"} |
find items for the process in a wait state |
{ id: instanceId, "items.status": 'wait' } |
check for items in "wait" |
{"items.status": "wait" , "items.elementId": "task_Buy" } |
find all items that has "wait" status |
findItems
performs the following
- Adds security conditions
-
Parses the query and converts it to MongoDB syntax
-
Issue mongoDB query; mongoDb returns instances (not items)
-
Filters the items and converts object into items
As an example if the api calls
- findItems query:
{"id":"e213ff1b-bb09-43cf-9392-665036903a2c","items.elementId":"task_clean"}
- it converts to:
{"id":"e213ff1b-bb09-43cf-9392-665036903a2c","items":{"$elemMatch":{"elementId":"task_clean"}}}
- returns on instance with several items
- it filters the items and returns only the 1 item as required
Instance Query#
Instance Queries are similar to Items Query but return entire Instances with all the items
// find instances having elementId
instances = await api.data.findInstances({
'items.elementId': 'task_Buy',
});
// find instance by itemd id
instances = await api.data.findInstances({ 'items.id': item.id });
// find instance by caseId
instances = await api.data.findInstances({ 'data.caseId': 3030 });
Input-Output Data#
Input and output is used in the following scenarios:
- Subprocess (input/output)
- Service Tasks (input/output)
- Call Tasks (input/output)
- Throw Message/Signal (input)
- Catch Message/Signal (output)
- User Task (input)
Input/Output using Scripts#
variable | description |
---|---|
data | refers to Instance Data or the token data for multi-instance tokens |
item.input | refers to input variable into the called task/event |
item.output | is the output of the called task/event |
<bpmn2:serviceTask id="Activity_00ticbc" name="Add 2 Using scripts" implementation="add" camunda:delegateExpression="add">
<bpmn2:extensionElements>
<camunda:executionListener event="start">
<camunda:script scriptFormat="JavaScript">
item.input.v1=33;
item.input.v2=25;
</camunda:script>
</camunda:executionListener>
<camunda:executionListener event="end">
<camunda:script scriptFormat="JavaScript">
item.data.result2= item.output + 100;
</camunda:script>
</camunda:executionListener>
</bpmn2:extensionElements>
Input/Output using Camunda Extension of Input/Output Parameter#
<bpmn2:serviceTask id="Task_0xh2iwa" name="service1" implementation="service1">
<bpmn2:extensionElements>
<camunda:inputOutput>
<camunda:inputParameter name="repeat">item.data.count</camunda:inputParameter>
<camunda:outputParameter name="sequence">this.output.seq</camunda:outputParameter>
<camunda:outputParameter name="returnText">'out text:'+this.output.text</camunda:outputParameter>
</camunda:inputOutput>
</bpmn2:extensionElements>
- parameter name is the name of variable
- value is a JavaScript expression
Scenario | before call | caller Syntax | after call |
---|---|---|---|
Throw Msg | parameters.var1= '123'; output.var1 |
throw(msg,parameters) | - |
Catch Msg | - | catch(msg,parameters) | data.var1= parameters.var1; |
Call Process | parameters.var1= '123'; | result=call(parameters) | data.var1= result.var1; |
Service Call | parameters.var1= '123'; | result=call(parameters) | data.var1= result.var1; |
Start Event | - | start(parameters) | data.var1= parameters.var1; data.var1=input.var1; |