Check string is empty, white space or null Logic Apps - azure-logic-apps

I am parsing CSV and checking if any item/string is empty/white space/null but none if the condition is not working!!
What I am doing wrong here?
Logic to check
Scenario
Parse CSV by each line and then by each column and check if string is empty/whitespace/null
If string is empty/whitespace/null
IscorrectCSV =False
Else
IscorrectCSV =True
INPUT 1
name,age
a1,34
a2,null
a3," "
a4,""
a5," 4"
A6,
EXPECTED OUTPUT 1
IscorrectCSV =False
INPUT 2
name,age
a1,34
a2,35
a3,36
EXPECTED OUTPUT 2
IscorrectCSV =True

First you need replace and instead of OR
remove first comparison and set variable before condition
First check if is equal null
Secondly check if the formula length() is equal to 0

After reproducing from my end, I could able to achieve this using below flow.
First I tried to form an Array from the sample csv given and then I used condition action inside a for-each loop to loop through second column item and check for the condition.
RESULTS:
You can reproduce the same in your logic app using the below code-view
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Array": {
"inputs": {
"variables": [
{
"name": "Array",
"type": "array",
"value": "#skip(split(outputs('Compose'),'\n'),1)"
}
]
},
"runAfter": {
"Compose": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Compose": {
"inputs": "name,age\na1,34\na2,NULL\na3, \na4,''\na5,",
"runAfter": {},
"type": "Compose"
},
"Compose_2": {
"inputs": "#variables('FinalArray')",
"runAfter": {
"For_each": [
"Succeeded"
]
},
"type": "Compose"
},
"FinalArray": {
"inputs": {
"variables": [
{
"name": "FinalArray",
"type": "array"
}
]
},
"runAfter": {
"Array": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"For_each": {
"actions": {
"Condition": {
"actions": {
"Append_to_array_variable": {
"inputs": {
"name": "FinalArray",
"value": "#{items('For_each')} - #{variables('IscorrectCSV')}"
},
"runAfter": {
"Set_IscorrectCSV_-_False": [
"Succeeded"
]
},
"type": "AppendToArrayVariable"
},
"Set_IscorrectCSV_-_False": {
"inputs": {
"name": "IscorrectCSV",
"value": false
},
"runAfter": {},
"type": "SetVariable"
}
},
"else": {
"actions": {
"Append_to_array_variable_2": {
"inputs": {
"name": "FinalArray",
"value": "#{items('For_each')} - #{variables('IscorrectCSV')}"
},
"runAfter": {
"Set_IscorrectCSV_-_True": [
"Succeeded"
]
},
"type": "AppendToArrayVariable"
},
"Set_IscorrectCSV_-_True": {
"inputs": {
"name": "IscorrectCSV",
"value": true
},
"runAfter": {},
"type": "SetVariable"
}
}
},
"expression": {
"or": [
{
"equals": [
"#slice(items('For_each'),add(indexOf(items('For_each'),','),1),length(items('For_each')))",
"NULL"
]
},
{
"equals": [
"#slice(items('For_each'),add(indexOf(items('For_each'),','),1),length(items('For_each')))",
" "
]
},
{
"equals": [
"#slice(items('For_each'),add(indexOf(items('For_each'),','),1),length(items('For_each')))",
"''"
]
},
{
"lessOrEquals": [
"#length(slice(items('For_each'),add(indexOf(items('For_each'),','),1),length(items('For_each'))))",
0
]
}
]
},
"runAfter": {},
"type": "If"
}
},
"foreach": "#variables('Array')",
"runAfter": {
"IscorrectCSV": [
"Succeeded"
]
},
"type": "Foreach"
},
"IscorrectCSV": {
"inputs": {
"variables": [
{
"name": "IscorrectCSV",
"type": "boolean"
}
]
},
"runAfter": {
"FinalArray": [
"Succeeded"
]
},
"type": "InitializeVariable"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {},
"triggers": {
"manual": {
"inputs": {
"schema": {}
},
"kind": "Http",
"type": "Request"
}
}
},
"parameters": {}
}

You can use the empty and trim expression together to find if the array item has some value

Related

Compare two versions in logic apps

I have two version strings and I need to compare them like the .NET Version type can (with awareness of Major, Minor versions, instead of just as strings) to see which one is newer. My question here is: How can I check which version string is newer in logic apps?
Is there any nicer way than the 'brute force' approach of string manipulation?
major = split(variables('CurrentImageVer', '.'))[0]
minor = split(variables('CurrentImageVer', '.'))[1]
and so on...
I agree with #Skin, Since the versions themselves are of string type, this can be done through string manipulation. Below is something that worked for me after reproducing from my end.
For demonstration purposes I have used the below 2 versions in an array variable.
[
"1.2.31",
"1.2.30"
]
Firstly, I have tried to split both the versions from the array.
Then I have used Condition connector to check if version 1 is greater or not than the other.
RESULTS:
Below is the complete JSON of my logic app.
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Compose": {
"inputs": "#variables('Latest Version')",
"runAfter": {
"Until": [
"Succeeded"
]
},
"type": "Compose"
},
"Flag": {
"inputs": {
"variables": [
{
"name": "Flag",
"type": "integer",
"value": 0
}
]
},
"runAfter": {
"Initialize_variable": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Initialize_variable": {
"inputs": {
"variables": [
{
"name": "Versions",
"type": "array",
"value": [
"1.2.31",
"1.2.30"
]
}
]
},
"runAfter": {},
"type": "InitializeVariable"
},
"Latest_Version": {
"inputs": {
"variables": [
{
"name": "Latest Version",
"type": "string",
"value": "Latest Not Found"
}
]
},
"runAfter": {
"Initialize_variable": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Split_Version1": {
"inputs": "#split(variables('Versions')[0],'.')",
"runAfter": {
"Latest_Version": [
"Succeeded"
]
},
"type": "Compose"
},
"Split_Version2": {
"inputs": "#split(variables('Versions')[1],'.')",
"runAfter": {
"Flag": [
"Succeeded"
]
},
"type": "Compose"
},
"Until": {
"actions": {
"Condition": {
"actions": {
"Set_variable_2": {
"inputs": {
"name": "Latest Version",
"value": "#{variables('Versions')[0]} is the latest version"
},
"runAfter": {},
"type": "SetVariable"
}
},
"else": {
"actions": {
"Condition_2": {
"actions": {
"Set_variable": {
"inputs": {
"name": "Latest Version",
"value": "#{variables('Versions')[1]} is the latest version"
},
"runAfter": {},
"type": "SetVariable"
}
},
"expression": {
"and": [
{
"less": [
"#outputs('Split_Version1')[variables('Flag')]",
"#outputs('Split_Version2')[variables('Flag')]"
]
},
{
"equals": [
"#variables('Latest Version')",
"Latest Not Found"
]
}
]
},
"runAfter": {},
"type": "If"
}
}
},
"expression": {
"and": [
{
"greater": [
"#outputs('Split_Version1')[variables('Flag')]",
"#outputs('Split_Version2')[variables('Flag')]"
]
},
{
"equals": [
"#variables('Latest Version')",
"Latest Not Found"
]
}
]
},
"runAfter": {},
"type": "If"
},
"Increment_variable": {
"inputs": {
"name": "Flag",
"value": 1
},
"runAfter": {
"Condition": [
"Succeeded"
]
},
"type": "IncrementVariable"
}
},
"expression": "#equals(variables('Flag'), length(outputs('Split_Version1')))",
"limit": {
"count": 60,
"timeout": "PT1H"
},
"runAfter": {
"Split_Version1": [
"Succeeded"
],
"Split_Version2": [
"Succeeded"
]
},
"type": "Until"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {},
"triggers": {
"manual": {
"inputs": {
"schema": {}
},
"kind": "Http",
"type": "Request"
}
}
},
"parameters": {}
}

How to construct a JSON when [keys] are seperated from [values] inside Logic App

I have been struggling with this for a long time to construct an output where my [key] is separated from my array value, please help to share your expertise.
Below is the response, i have received from Azure Alert and I'm looking forward to create an output (refer Expected Output image).
{
"tables": [
{
"columns": [
{
"name": "task",
"type": "string"
},
{
"name": "environment",
"type": "string"
},
{
"name": "workspace",
"type": "string"
}
],
"name": "PrimaryResult",
"rows": [
[
"job_name_1",
"PRODUCTION",
"WORKSPACE-1",
],
[
"job_name_2",
"TEST",
"WORKSPACE-2",
]
]
}
]
}
Inside Logic App. I have parsed the json and used a lot of for each loop variations but, every single time, i get stuck in traversing the rows as its a 2d array. Even though, i traverse them, i cannot associate them with columns. Any alternative approaches will be appreciated ?
Input
Expected Output
[
{
"task": "job_name_1",
"environment": "PRODUCTION",
"workspace" : "WORKSPACE-1"
},
{
"task": "job_name_2",
"environment": "TEST",
"workspace" : "WORKSPACE-2"
}
]
I'd be lying if I said this was straight forward but you can load the below definition into your tenant and see a working version.
Note: I made the assumption that you only ever have one table in your top level array given that's what you provided in your question.
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"For_Each_Row": {
"actions": {
"Append_To_Transformed_Array": {
"inputs": {
"name": "Transformed Array",
"value": "#variables('Row Object')"
},
"runAfter": {
"For_Each_Column": [
"Succeeded"
]
},
"type": "AppendToArrayVariable"
},
"For_Each_Column": {
"actions": {
"Add_Property_To_Temp_Row_Object": {
"inputs": {
"name": "Temp Row Object",
"value": "#addProperty(variables('Row Object'), variables('Columns')?[variables('Column Index')]['name'], items('For_Each_Column'))"
},
"runAfter": {},
"type": "SetVariable"
},
"Increment_Column_Index": {
"inputs": {
"name": "Column Index",
"value": 1
},
"runAfter": {
"Set_Row_Object_From_Temp_Row_Object": [
"Succeeded"
]
},
"type": "IncrementVariable"
},
"Set_Row_Object_From_Temp_Row_Object": {
"inputs": {
"name": "Row Object",
"value": "#variables('Temp Row Object')"
},
"runAfter": {
"Add_Property_To_Temp_Row_Object": [
"Succeeded"
]
},
"type": "SetVariable"
}
},
"foreach": "#item()",
"runAfter": {
"Reset_Column_Index": [
"Succeeded"
]
},
"type": "Foreach"
},
"Reset_Column_Index": {
"inputs": {
"name": "Column Index",
"value": 0
},
"runAfter": {
"Reset_Temp_Row_Object": [
"Succeeded"
]
},
"type": "SetVariable"
},
"Reset_Row_Object": {
"inputs": {
"name": "Row Object",
"value": {}
},
"runAfter": {},
"type": "SetVariable"
},
"Reset_Temp_Row_Object": {
"inputs": {
"name": "Temp Row Object",
"value": {}
},
"runAfter": {
"Reset_Row_Object": [
"Succeeded"
]
},
"type": "SetVariable"
}
},
"foreach": "#variables('Rows')",
"runAfter": {
"Initialize_Column_Index": [
"Succeeded"
]
},
"runtimeConfiguration": {
"concurrency": {
"repetitions": 1
}
},
"type": "Foreach"
},
"Initialize_Column_Index": {
"inputs": {
"variables": [
{
"name": "Column Index",
"type": "integer"
}
]
},
"runAfter": {
"Initialize_Temp_Row_Object": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Initialize_Columns": {
"inputs": {
"variables": [
{
"name": "Columns",
"type": "array",
"value": "#variables('Data')?['tables'][0]['columns']"
}
]
},
"runAfter": {
"Initialize_Data": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Initialize_Data": {
"inputs": {
"variables": [
{
"name": "Data",
"type": "object",
"value": {
"tables": [
{
"columns": [
{
"name": "task",
"type": "string"
},
{
"name": "environment",
"type": "string"
},
{
"name": "workspace",
"type": "string"
}
],
"name": "PrimaryResult",
"rows": [
[
"job_name_1",
"PRODUCTION",
"WORKSPACE-1"
],
[
"job_name_2",
"TEST",
"WORKSPACE-2"
]
]
}
]
}
}
]
},
"runAfter": {},
"type": "InitializeVariable"
},
"Initialize_Row_Object": {
"inputs": {
"variables": [
{
"name": "Row Object",
"type": "object"
}
]
},
"runAfter": {
"Initialize_Transformed_Array": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Initialize_Rows": {
"inputs": {
"variables": [
{
"name": "Rows",
"type": "array",
"value": "#variables('Data')?['tables'][0]['rows']"
}
]
},
"runAfter": {
"Initialize_Columns": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Initialize_Temp_Row_Object": {
"inputs": {
"variables": [
{
"name": "Temp Row Object",
"type": "object",
"value": {}
}
]
},
"runAfter": {
"Initialize_Row_Object": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Initialize_Transformed_Array": {
"inputs": {
"variables": [
{
"name": "Transformed Array",
"type": "array"
}
]
},
"runAfter": {
"Initialize_Rows": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Result": {
"inputs": "#variables('Transformed Array')",
"runAfter": {
"For_Each_Row": [
"Succeeded"
]
},
"type": "Compose"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {},
"triggers": {
"manual": {
"inputs": {
"method": "GET",
"schema": {}
},
"kind": "Http",
"type": "Request"
}
}
},
"parameters": {}
}
The main challenges I see with having to do this are ...
The lack of ability to self reference. Because of that, I had to use a Row Object in conjunction with a Temp Row Object when adding the property each time.
The amount of nesting is a little hard to follow but it works.
Performance will be a real burden if you have a lot of rows.
One thing to note is the outer For Each action needs to have the concurrency set to 1, if it's not, you'll run into problems.
This is the end result as you were wanting ...

How to assign JSON field from one data source to another in Logic App

I have two different JSON data coming into my Logic App:
Data 1:
[
{
"EmployeeCode":"123",
"Username":"abc"
},
{
"EmployeeCode":"456",
"Username":"def"
}
]
Data 2:
[
{
"EmployeeCode":"123",
"Team":"IT"
},
{
"EmployeeCode":"456",
"Team":"Finance"
}
]
And I want to generate final output like this:
Final output:
[
{
"EmployeeCode":"123",
"Username":"abc",
"Team":"IT"
},
{
"EmployeeCode":"456",
"Username":"def",
"Team":"Finance"
}
]
Is there a simple way to achieve this in Logic App itself? Without using JavaScript or Azure Function or anything?
After reproducing from our end here is how we could able to achieve your requirement.
First, we have used 2 Parse JSON for each data to extract the items in the JSON.
then used a condition connector to compare the EmployeeCode, and then merged using compose connector.
However to make the whole JSON to be used for future purposes we have initialized an array variable and then appended the successful runs from the condition connector. Here is my logic app.
RESULTS:
Below is the code view of my logic app
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"FinalJSON": {
"inputs": "#variables('FinalJson')",
"runAfter": {
"For_each": [
"Succeeded"
]
},
"type": "Compose"
},
"For_each": {
"actions": {
"For_each_2": {
"actions": {
"Condition": {
"actions": {
"Append_to_array_variable": {
"inputs": {
"name": "FinalJson",
"value": "#outputs('Compose')"
},
"runAfter": {
"Compose": [
"Succeeded"
]
},
"type": "AppendToArrayVariable"
},
"Compose": {
"inputs": {
"EmployeeCode": "#{items('For_each')['EmployeeCode']}",
"Team": "#{items('For_each_2')['Team']}",
"Username": "#{items('For_each')['Username']}"
},
"runAfter": {},
"type": "Compose"
}
},
"expression": {
"and": [
{
"equals": [
"#items('For_each')['EmployeeCode']",
"#items('For_each_2')['EmployeeCode']"
]
}
]
},
"runAfter": {},
"type": "If"
}
},
"foreach": "#body('Parse_JSON2')",
"runAfter": {},
"type": "Foreach"
}
},
"foreach": "#body('Parse_JSON1')",
"runAfter": {
"Initialize_variable": [
"Succeeded"
]
},
"type": "Foreach"
},
"Initialize_variable": {
"inputs": {
"variables": [
{
"name": "FinalJson",
"type": "array"
}
]
},
"runAfter": {
"Parse_JSON2": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"JSON1": {
"inputs": [
{
"EmployeeCode": "123",
"Username": "abc"
},
{
"EmployeeCode": "456",
"Username": "def"
}
],
"runAfter": {},
"type": "Compose"
},
"JSON2": {
"inputs": [
{
"EmployeeCode": "123",
"Team": "IT"
},
{
"EmployeeCode": "456",
"Team": "Finance"
}
],
"runAfter": {
"JSON1": [
"Succeeded"
]
},
"type": "Compose"
},
"Parse_JSON1": {
"inputs": {
"content": "#outputs('JSON1')",
"schema": {
"items": {
"properties": {
"EmployeeCode": {
"type": "string"
},
"Username": {
"type": "string"
}
},
"required": [
"EmployeeCode",
"Username"
],
"type": "object"
},
"type": "array"
}
},
"runAfter": {
"JSON2": [
"Succeeded"
]
},
"type": "ParseJson"
},
"Parse_JSON2": {
"inputs": {
"content": "#outputs('JSON2')",
"schema": {
"items": {
"properties": {
"EmployeeCode": {
"type": "string"
},
"Team": {
"type": "string"
}
},
"required": [
"EmployeeCode",
"Team"
],
"type": "object"
},
"type": "array"
}
},
"runAfter": {
"Parse_JSON1": [
"Succeeded"
]
},
"type": "ParseJson"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {},
"triggers": {
"manual": {
"inputs": {
"schema": {}
},
"kind": "Http",
"type": "Request"
}
}
},
"parameters": {}
}

How to return index of array where value matches string variable?

I'm extracting a .txt into an array, line by line.
After doing that, I want to check for a match between a string variable and an element in the array(contains, does not have to be exact match), and return the index of said element.
Is there any solution to this?
I've both tried working with for-each loops and until-loops, but so far the app is iterating until it times out.
Considering this to be my .txt file
In the beginning, I'm just retrieving the text file and converting each line into an array.
Then I have Initialised 2 Variables and set Index to 0 and Status to false.
In the next step I'm using Until Connector, looping through the Array using outputs('Convert_txt_into_array')[variables('Index')] and check until the status is set to true.
So, Whether the status becomes true or false the index increments by 1 and loops through the Until connector. If the condition becomes true then the Index Variable is set to the current iteration by using iterationIndexes which gives us the current iteration and exits the Until block.
And Finally, I'm printing Index Variable in Compose connector for future usage [This step can be avoided].
RESULT - 1 :
RESULT - 2 :
Codeview of my logic app
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Compose": {
"inputs": "The #{variables('FindingString')} is at index : #{variables('Index')}",
"runAfter": {
"Until": [
"Succeeded"
]
},
"type": "Compose"
},
"Convert_txt_into_array": {
"inputs": "#split(body('Get_blob_content_(V2)'),'\r\n')",
"runAfter": {
"FindingString": [
"Succeeded"
]
},
"type": "Compose"
},
"FindingString": {
"inputs": {
"variables": [
{
"name": "FindingString",
"type": "string",
"value": "age-34"
}
]
},
"runAfter": {
"Get_blob_content_(V2)": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Get_blob_content_(V2)": {
"inputs": {
"host": {
"connection": {
"name": "#parameters('$connections')['azureblob_1']['connectionId']"
}
},
"method": "get",
"path": "/v2/datasets/#{encodeURIComponent(encodeURIComponent('AccountNameFromSettings'))}/files/#{encodeURIComponent(encodeURIComponent('JTJmY29udGFpbmVyJTJmc2FtcGxlVGV4dEZpbGUudHh0'))}/content",
"queries": {
"inferContentType": true
}
},
"metadata": {
"JTJmY29udGFpbmVyJTJmc2FtcGxlVGV4dEZpbGUudHh0": "/container/sampleTextFile.txt"
},
"runAfter": {},
"type": "ApiConnection"
},
"Index": {
"inputs": {
"variables": [
{
"name": "Index",
"type": "integer",
"value": 0
}
]
},
"runAfter": {
"Convert_txt_into_array": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Status": {
"inputs": {
"variables": [
{
"name": "Status",
"type": "boolean",
"value": false
}
]
},
"runAfter": {
"Index": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Until": {
"actions": {
"Condition": {
"actions": {
"Set_Index": {
"inputs": {
"name": "Index",
"value": "#iterationIndexes('Until')"
},
"runAfter": {
"Set_Status_as_True": [
"Succeeded"
]
},
"type": "SetVariable"
},
"Set_Status_as_True": {
"inputs": {
"name": "Status",
"value": "#true"
},
"runAfter": {},
"type": "SetVariable"
}
},
"else": {
"actions": {
"Set_Status_as_False": {
"inputs": {
"name": "Status",
"value": "#false"
},
"runAfter": {},
"type": "SetVariable"
}
}
},
"expression": {
"and": [
{
"equals": [
"#outputs('Convert_txt_into_array')[variables('Index')]",
"#variables('FindingString')"
]
}
]
},
"runAfter": {},
"type": "If"
},
"Increment_variable": {
"inputs": {
"name": "Index",
"value": 1
},
"runAfter": {
"Condition": [
"Succeeded"
]
},
"type": "IncrementVariable"
}
},
"expression": "#equals(variables('Status'), true)",
"limit": {
"count": 60,
"timeout": "PT1H"
},
"runAfter": {
"Status": [
"Succeeded"
]
},
"type": "Until"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {
"$connections": {
"defaultValue": {},
"type": "Object"
}
},
"triggers": {
"manual": {
"inputs": {
"schema": {}
},
"kind": "Http",
"type": "Request"
}
}
},
"parameters": {
"$connections": {
"value": {
"azureblob_1": {
"connectionId": "/subscriptions/<Your_Subscription_Id>/resourceGroups/<Your_Resource_Group_Name>/providers/Microsoft.Web/connections/azureblob-1",
"connectionName": "azureblob-1",
"id": "/subscriptions/<Your_Subscription_Id>/providers/Microsoft.Web/locations/northcentralus/managedApis/azureblob"
}
}
}
}
}
This solution may not be for you but it's an option.
When you process your CSV data, instead of just adding line by line to the array, you could add an object that contains the index of each row (starting from 0). This is an example of what I mean ...
CSV File
This is a test 1
This is a test 2
This is a test 3
This is a test 4
Reference Array Variable (with objects)
[
{
"Index": 0,
"Text": "This is a test 1"
},
{
"Index": 1,
"Text": "This is a test 2"
},
{
"Index": 2,
"Text": "This is a test 3"
},
{
"Index": 3,
"Text": "This is a test 4"
}
]
You can then filter that array using the Filter array data operation like so ...
Left Side Expression = item()?['Text']
Right Side Expression = string(3) (I'm searching for a string of 3 but because it's a number, I need to treat it slightly differently, it's unlikely you'll have this problem)
That filter produces this result ...
... from which you can get the index of the first found item ...
This is the expression ...
if(greater(length(body('Filter_array')), 0), first(body('Filter_array'))['Index'], -1)
... and there you go ...
This is the JSON definition if you're interested.
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Filter_array": {
"inputs": {
"from": "#variables('Reference Array')",
"where": "#contains(item()?['Text'], string(3))"
},
"runAfter": {
"Initialize_Reference_Array": [
"Succeeded"
]
},
"type": "Query"
},
"Initialize_Found_Index": {
"inputs": {
"variables": [
{
"name": "Found Index",
"type": "integer",
"value": "#if(greater(length(body('Filter_array')), 0), first(body('Filter_array'))['Index'], -1)"
}
]
},
"runAfter": {
"Filter_array": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Initialize_Reference_Array": {
"inputs": {
"variables": [
{
"name": "Reference Array",
"type": "array",
"value": [
{
"Index": 0,
"Text": "This is a test 1"
},
{
"Index": 1,
"Text": "This is a test 2"
},
{
"Index": 2,
"Text": "This is a test 3"
},
{
"Index": 3,
"Text": "This is a test 4"
}
]
}
]
},
"runAfter": {},
"type": "InitializeVariable"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {},
"triggers": {
"Recurrence": {
"evaluatedRecurrence": {
"frequency": "Month",
"interval": 3
},
"recurrence": {
"frequency": "Month",
"interval": 3
},
"type": "Recurrence"
}
}
},
"parameters": {}
}

Azure Logic App Condition does not work in loop if based on changing values

I need to write a simple LogicApp that connects to a http endpoint, receives some JSON, loops though the JSON message and submits it to a different http endpoint in chunks based on a value in the message.
In doing this I've come to the conclusion that Conditions inside For Each loop always evaluate the conditions before the loop and executes the path that matched the result before the loop, even though the result should have changed as the some variables have been updated in the loop.
I've managed to illustrate the problem with the below example.
{
"definition": {
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"actions": {
"Compose": {
"inputs": "#variables('TestStr')",
"runAfter": {
"Compose_3": [
"Succeeded"
]
},
"type": "Compose"
},
"Compose_3": {
"inputs": "#variables('TestArray')",
"runAfter": {
"For_each": [
"Succeeded"
]
},
"type": "Compose"
},
"For_each": {
"actions": {
"Compose_2": {
"inputs": "#variables('TestArray')",
"runAfter": {
"Condition": [
"Succeeded"
]
},
"type": "Compose"
},
"Condition": {
"actions": {
"Append_to_array_variable": {
"inputs": {
"name": "TestArray",
"value": "#items('For_each')"
},
"runAfter": {},
"type": "AppendToArrayVariable"
},
"Set_variable_2": {
"inputs": {
"name": "TestStr",
"value": "XXXX"
},
"runAfter": {
"Append_to_array_variable": [
"Succeeded"
]
},
"type": "SetVariable"
}
},
"else": {
"actions": {
"Set_variable": {
"inputs": {
"name": "TestStr",
"value": "not"
},
"runAfter": {},
"type": "SetVariable"
}
}
},
"expression": {
"and": [
{
"equals": [
"#variables('TestStr')",
"BlankValue"
]
}
]
},
"runAfter": {},
"type": "If"
}
},
"foreach": "#variables('FullArray')",
"runAfter": {
"Initialize_variable_3": [
"Succeeded"
]
},
"type": "Foreach"
},
"Initialize_variable": {
"inputs": {
"variables": [
{
"name": "TestStr",
"type": "String",
"value": "BlankValue"
}
]
},
"runAfter": {},
"type": "InitializeVariable"
},
"Initialize_variable_2": {
"inputs": {
"variables": [
{
"name": "TestArray",
"type": "Array"
}
]
},
"runAfter": {
"Initialize_variable": [
"Succeeded"
]
},
"type": "InitializeVariable"
},
"Initialize_variable_3": {
"inputs": {
"variables": [
{
"name": "FullArray",
"type": "Array",
"value": [
{
"key": "value1"
},
{
"key": "value2"
},
{
"key": "value3"
}
]
}
]
},
"runAfter": {
"Initialize_variable_2": [
"Succeeded"
]
},
"type": "InitializeVariable"
}
},
"contentVersion": "1.0.0.0",
"outputs": {},
"parameters": {},
"triggers": {
"Recurrence": {
"recurrence": {
"frequency": "Month",
"interval": 3
},
"type": "Recurrence"
}
}
}
}
I would expect the below LogicApp to execute the loop three times, every time evaluate the condition and execute array insert only once, with the TestArray containing one entry of
{
"key":"value1"
}
and string TestStr having value of 'not'
But the actual results seem to differ - TestArray contains all three entries from FullArray and TestStr is 'XXXX'
What am I missing here? Are there any workarounds?
I've discovered the reason for this behaviour. Posting here if anyone comes across this in the future.
For_each loops are executed in parallel by default. That is why the conditions are evaluated for all iterations before the loop starts.
There is a way of switching this off - in the Settings you can switch on concurrency control and set parallelism to 1

Resources