Merging variables from the job worker and the process instance

Minh Trần: Hi All,

I don’t know if this is right place to ask about variable mappings. In our case, we need to build an output mapping between two variables (has same name) as following:

The mapping will semantically merge each file in the right array into the left array based on id.

Please give any suggestion,
Thanks

Minh Trần: Any idea?

zell: Not 100% sure whether I get your example but maybe this comment helps on merging variables.

Minh Trần: Yes please

zell: https://github.com/camunda-cloud/zeebe/issues/297#issuecomment-734393279|https://github.com/camunda-cloud/zeebe/issues/297#issuecomment-734393279

zell: Sorry i though i shared it:see_no_evil: :sweat_smile:

Minh Trần: Thank <@U6WCLLNGJ>,

I checked the comment, however I think it’s different from my case.
I implemented something with source:
1. for f in files return // => This is the files returned from Service Task
2. for f1 in files return // => I expected this files is the files in zeebe, but it’s running with files from Service Task
3. if f.id = f1.id return
4. appendTo(f, f1)

Line 1 and 2 has the same list files, so it runs into wrong result.
Is there any way to indicate ?
• Line 1: is the files returned from Service Task
• Line 2: is the current files in zeebe
Best,

saig0: If both variables have the same name then you can’t distinguish. But you could rename or wrap the variable from the service task, for example, rename to "updatedFiles" or {"updated": {"files":[..]}}.

saig0: If you want to merge one array into the other array (service task updates the process instance variables) then you could use the following expression:

for f in updated.files return put all(f, files[id=f.id][1]) 

saig0: If the updates array contains more elements (like in your example) then you need to deal with null (i.e. not existing entries). For example, by using an if x != null then x else {} check.

saig0: Finally, if you need a two-way merge then it gets a bit complicated. For example, using the following expression:

 {
 ids: union(files.id,updated.files.id),
 getById: function (files,id) if (count(files[id=id]) &gt; 0) then files[id=id][1] else {},
 result: for id in ids return put all(getById(files, id), getById(updates.files, id))
 }.result 

saig0: Does this help you?

Minh Trần: Thank <@U6XL8AN3V>,

Thank for your answer, that is also exactly what we did while waiting for your support.
Additionally, we put an additional mapping to set the variable updated into null , then it is not moved to the following nodes. I mean, if the updated goes to the next node, then it will run into the input mappings of that node, that I don’t expect.

Minh Trần: Yes <@U6XL8AN3V>,

It’s really help. I just wonder because it causes the change on our job workers (existing microservices) to complete the job with a different variable name.

saig0: You could avoid changing the worker by using another mapping. You could map the variable from the job worker to a different variable (i.e. updated). If this mapping is above the other, then you can use the new variable in the mapping.

Note: This post was generated by Slack Archivist from a conversation in the Zeebe Slack, a source of valuable discussions on Zeebe (get an invite). Someone in the Slack thought this was worth sharing!

If this post answered a question for you, hit the Like button - we use that to assess which posts to put into docs.

Minh Trần: Yes, I did tried this, and worked.

However, we worried about the execution order of the mappings. Are you sure that the above one will execute before the lower one ?

saig0: Yes. The mappings are evaluated in order (always). It is mentioned in the docs: https://docs.camunda.io/docs/product-manuals/concepts/variables#inputoutput-variable-mappings