blog.atwork.at

news and know-how about microsoft, technology, cloud and more.

Azure Logic Apps Toolbox 10-Dynamic access to keys and values ​​in a JSON object

In Azure Logic Apps, looping through objects is a common requirement. When we have prior knowledge of an object's properties, the process is straightforward. However, things get more challenging when attempting to access properties dynamically. See a method to access data in a JSON object dynamically here.

JSON (JavaScript Object Notation) is a format for storing and transferring data. Here we want to dynamically access data from a JSON object in an Azure Logic App. To demonstrate this, consider this example.

A simple object

In this sample, we create a new flow with a trigger. We add a variable data of type object that is filled with 3 colors Red, Green and Blue.

{
     "color1": "Red",
     "color2": "Green",
     "color3": "Blue" }

The object in JSON format looks as here. Then we add another variable colors, of type string, and add the data object onto the Value, as above.

image

When we run the Logic App, the data is automatically converted to a string, containing all values:

{"color1":"Red","color2":"Green","color3":"Blue"}

In the designer, we see the flow with it´s data values.

image

Access a specific property

We can also easily access a specific property. We just have to know the property name. We change the expression for the colors variable as here:

variables('data')?['color2']

The syntax is to refer to the object, then navigate to the property. The key name here is color2.

image

When we run the Logic App now, we see the expected result: We get only Green as the Value in the colors string.

image

Going deeper

Objects can be more complex and store a lot of data. The advantage of using data in JSON format is the high flexibility and the relatively low overhead for describing the data.

We change the data object and add a section colors (a new key) that includes the 3 colors, as here.

{
  "colors": {
    "color1": "Red",
    "color2": "Green",
    "color3": "Blue"
  }
}

In this sample, the expression to access color2 would look like this:

variables('data')?['colors']?['color2']

image

When we run the flow now, we get the same result showing color Green.

image

Note: Unfortunately, we cannot access a property of an object by the index number. When we try to get the 2. property color2  of the colors item (the index always starts with 0) with the following expression...

variables('data')?['colors']?[1] - this does NOT work

...we get an error: "The template language expression 'variables('data')?['colors']?[1]' cannot be evaluated because property '1' cannot be selected. Object properties can only be selected by names. Please see https://aka.ms/logicexpressions for usage details.".  So, wee need to use property names (key names) to access them. That´s why we need the workaround below.

We could only use index number if the object contains an array, like variables('data')[1] to get the 2. record (which is not the case in our sample, data is a single object, not an array).

So far, so good.

Working with data operations

In certain scenarios, it becomes necessary to dynamically access a property within an object in Azure Logic Apps. My use case involved comparing two objects to identify and to document their differing values.

Unfortunately, there is currently no built-in method to access an object key dynamically (like color1, color2, or color3 here), and we saw that we cannot access the property by an index number. The Javascript keys() function (or a similar equivalent) does not exist in Azure Logic Apps. On the other hand, some actions can only operate with arrays (such as for-loop actions, contains, filter, join, select, etc.), but not with objects. For a comprehensive list of valid JSON functions, refer to the documentation on performing data operations in Azure Logic Apps at Perform data operations in Azure Logic Apps.

image

We see, there are some actions available for arrays, but not so many for JSON operations. Certainly, for extracting data there are workarounds available, such as utilizing an integration account with JavaScript code, leveraging an Azure Function and developing custom code, or other methods.

However, for the sake of simplicity, I opted to stay within the flow and find a straightforward solution. Although I didn't discover a direct workaround for iterating through all properties of an object in a loop, I did find an alternative solution.

Dynamically access a property

Remember that we can access a property of an object by its name?

variables('data')?['color2']

So, we can use another variable myprop with a value, and replace the name with a variable as well:

variables('data')?[variables('myprop')]

As above, we need to know the name of the property, but the access can be done dynamically. Furthermore, we can enhance the solution by incorporating a query of the object - and that can be very useful, too.

Here we initialize the value of myprop with the following query in the Initialize variable 3 action, before we use it below:

colors/color2

This is the new flow, using a dynamic property to access data from the data object.

image

The output is as expected. We get color Green!

image

Isn´t that cool? Winking smile

Compare data objects and show differences

Since we can now dynamically access data in an object, it is obvious that we can control the content of the variable ourselves.

Coming back to my use case, I want to compare data in two objects, and find out only changed values. One idea would be to build our own array that contains the relevant property names. We can go through this array in a for-each loop (data must be available in an array) and read data from the object and, if necessary, save the values ​​in our own result object or array. I took this route for my use case. 

So, how can we create a flow to compare two data objects?

First, we create a new flow with a trigger and add a 4th value to the simple data object so that it contains Red, Green, Blue, and Gold. Then, we add another variable named myfilter. That variable is of type array and stores the keys we are interested in. In our sample, we only want to compare color1, color2, and color3 with another data object. We ignore any values that are stored in other keys, such as color4.

image

Now we add another variable named comparedata of type object. This object contains 3 different colors. color1 is Red-ish, color3 is Purple, and color4 is Yellow. color2 is still Green (as in the data object). We also add another variable named colors of type array to store the result. colors shall be filles with all keys and values that are different between data and comparedata.

image

Now we have the prerequisites for the task. We need to run through our myfilter array in a for-each loop and compare the items from the two data objects.

We add a for-each loop, using the myfilter array. We want to run through our 3 items (color1, color2, color3). Then we add a condition. The following screenshot shows the rest of the Logic App.

image

Within the loop, we can access the current item with the item() expression. For the 1st item, item() is color1, for the 2nd, color2, etc.

The condition looks as here: We compare the values of data/key with comparedata/key.

...
"expression": {
     "and": [
         {
             "not": {
                 "equals": [
                     "@variables('data')?[item()]",
                     "@variables('comparedata')?[item()]"
                 ]
             }
         }
     ] },
...

At run time this is interpreted similar as here:

If data/color1.value not equals comparedata/color1.value

If the condition is true, the two values are different. Then, we add the compared key name and the new value from comparedata to our result array colors.

...
"actions": {
     "Append_to_array_variable": {
         "inputs": {
             "name": "colors",
             "value": {
                 "@{item()}": "@{variables('comparedata')?[item()]}"
             }
         },
         "runAfter": {},
         "type": "AppendToArrayVariable"
     } }, ...

If the condition is not met, this means that the values are identical, and we ignore these keys and values.

The logic is done. To see the result, we add another variable result of type string at the end of the flow, after the for-each loop that combines the colors array with the Join() function into a string.

...
"showresult": {
     "inputs": {
         "variables": [
             {
                 "name": "result",
                 "type": "string",
                 "value": "@{join(variables('colors'),',')}"
             }
         ]
     }, ...

Let´s try it out! When we run the flow, we get this result. We can see the output of the flow in a nice way.

image

The loop ran 3 times (color1 to color3) as defined in our myfilter array. This means, the logic ignored color4. We see that the result shows two different values, color1 is Red-ish, and color3 is Purple.

So, the logic compared specific keys and values and created an output with the differences. Mission accomplished.

If you want to try it out yourself, you can find this Logic App in my GitHub repo at https://github.com/tonipohl/AzureAndGraph/blob/main/LogicApps/Compare-data-objects-dynamically.json.

Further considerations

Even though there are alternatives, I find this method very useful. It allows to solve small operations within the Azure Logic Apps environment without the need to include other external resources and coding.

I hope this step-by-step article and the tip how to dynamically access data objects helps other Logic App users to design their own flows accordingly.

Loading