Foreach
The foreach
state requires the array
attribute to loop over. The difference to other states is that the data in the action of the foreach
function is not getting the state data of the flow but the values provided in the array.
Simple Foreach
This is the most basic example. It shows that each action call in the foreach loop has it's own object during execution. In the flow scope there is a variable .names
. But the array
definition uses jq to iterate through .names
and creates a list of JSON objects with the variable name
. This means that each action only sees an object with the value name
and has no access to names
.
direktiv_api: workflow/v1
functions:
- id: echo
image: direktiv/echo:dev
type: knative-workflow
states:
- id: data
type: noop
log: preparing foreach data
transform:
names:
- hello
- world
- goodbye
transition: foreach
- id: foreach
type: foreach
array: 'jq([.names[] | { name: . }])'
action:
function: echo
input: 'jq(.)'
The output for this flow should be something like the following:
{
"names": [
"hello",
"world",
"goodbye"
],
"return": [
{
"name": "hello"
},
{
"name": "world"
},
{
"name": "goodbye"
}
]
}
Foreach with JQ
This examples shows how to use JQ for a more complex foreach scenario. It generates an array based on .data
in the first state. The JQ command is storing the state data .otherdata
in the variable od
. This result will be piped into the actual array generation with .data[]
. In this case it is more obvious how each foreach
action gets it's own JSON object. In this case the JQ command sets the name
to the name in the array, time
to the actual time with the JQ time
function. The last attribute otherdata
passes the original value from the flow state data into the action.
direktiv_api: workflow/v1
functions:
- id: echo
image: direktiv/echo:dev
type: knative-workflow
states:
- id: data
type: noop
transform:
data:
- name: key1
value: value1
- name: key2
value: value2
- name: key3
value: value3
otherdata: somedata
transition: foreach
- id: foreach
type: foreach
array: 'jq(.otherdata as $od | [.data[] | { name: .name, time: now, otherdata: $od }])'
action:
function: echo
input: 'jq(.)'
{
"data": [
{
"name": "key1",
"value": "value1"
},
{
"name": "key2",
"value": "value2"
},
{
"name": "key3",
"value": "value3"
}
],
"otherdata": "somedata",
"return": [
{
"name": "key1",
"otherdata": "somedata",
"time": 1680972341.2246315
},
{
"name": "key2",
"otherdata": "somedata",
"time": 1680972341.224634
},
{
"name": "key3",
"otherdata": "somedata",
"time": 1680972341.2246354
}
]
}
Foreach with JS
This example uses Javascript to achieve the same outcome. If data structures are getting too complex it might be better to use Javascript for readability. If Javascript is used Direktiv passes in an object data
which contains the flow state. Data can be accessed in the usual way like data["otherdata"]
. In the case of a foreach
the Javascript function needs to return an array.
direktiv_api: workflow/v1
functions:
- id: echo
image: direktiv/echo:dev
type: knative-workflow
states:
- id: data
type: noop
transform:
data:
- name: key1
value: value1
- name: key2
value: value2
- name: key3
value: value3
otherdata: somedata
transition: foreach
- id: foreach
type: foreach
array: |
js(
// empty array
const items = []
// loop over "data" attribute created in first state of flow
for (let i = 0; i < data["data"].length; i++) {
// create object and set attributes
item = new Object();
item.name = data["data"][i]["name"]
item.time = Date.now()
item.otherdata = data["otherdata"]
// add item
items[i] = item
}
// return array of items
return items
)
action:
function: echo
input: 'jq(.)'