Contact Us 1-800-596-4880

For Each (<foreach/>)

logo cloud IDE Cloud IDE

logo desktop IDE Desktop IDE

Process input in a pattern similar to for-each or for loop in other programming languages.

Component XML

This component supports the following XML structure:

<foreach doc:name="For Each"
  doc:id="119e4859"
  collection="#[payload]"
  counterVariableName="counter"
  batchSize="1"
  rootMessageVariableName="rootMessage" />

For Each (<foreach/>) attributes are configurable through the UI and XML.

Attribute Name Attribute XML Description

Foreach (default)

doc:name

Editable name for the component to display in the canvas.

N/A

doc:id

Automatically generated identifier for the component.

Collection

collection

A DataWeave expression that returns a Java collection, object, array, map, or DOM nodes. For Each automatically splits the collection into elements, such as the highest-level objects in a JSON array of objects. Each element becomes the payload on which a processor within For Each acts. For Each accepts collections of any supported content type, such as application/json, application/java, or application/xml. Defaults to payload.

Batch size

batchSize

Number that the scope uses to partition the collected elements from the input into sub-collections of a specified size. For example, if input to For Each is an array of 199 elements and you set the batch size to 50, the scope produces three arrays of 50 elements each and one array of 49 elements. Defaults to 1.

Root message variable name

rootMessageVariableName

Configurable name of the variable that stores the complete, un-split Mule message from the original input to For Each. The message contains the payload and any attributes but does not contain any variables (vars), which are part of the Mule event that contains the Mule message. Within For Each, you can gain access to the value of the payload of the message with vars.rootMessage.payload and to attributes of the message with vars.rootMessage.attributes. For Each consumes this variable, so you can access it only from within the scope. Outside For Each, the variable returns null. Defaults to rootMessage.

Counter variable name

counterVariableName

Name of the variable that assigns a number to each iteration over a given element. The sequence starts with 1 and proceeds sequentially. Using the default name of this property (counter), you can access this number with vars.counter. For Each consumes this variable, so it is not available and returns null when used outside of the scope. Defaults to counter.

Examples

The following example collects and splits an array of objects that it receives into separate objects. Components within the scope select a portion of each object, write a portion of that selected content into separate files, and log the new payload that results within For Each.

Assume that For Each receives its input from a scheduled HTTP request for this JSON array of objects.

(1)
<foreach doc:name="For Each" collection="#[payload]">
  (2)
  <ee:transform doc:name="Transform Message" >
    <ee:message >
      <ee:set-payload ><![CDATA[%dw 2.0
output application/json
---
payload.company]]></ee:set-payload>
    </ee:message>
  </ee:transform>
  (3)
  <file:write doc:name="Write"
    path='#[(payload.name replace " " with("-") ++ "-") ++ (now() as String {format: "uuuuMMddHHmmss"}) ++ ".json"]'
    config-ref="File_Config" mode="CREATE_NEW"/>
  (4)
  <logger level="INFO" doc:name="Logger" message="#[payload]"/>
</foreach>

For Each processes the input array:

1 For Each (<foreach />) collects the entire input payload and splits it into the ten top-level JSON objects within it, such as this one:
{
  "id": 1,
  "name": "Leanne Graham",
  "username": "Bret",
  "email": "Sincere@april.biz",
  "address": {
    "street": "Kulas Light",
    "suite": "Apt. 556",
    "city": "Gwenborough",
    "zipcode": "92998-3874",
    "geo": {
      "lat": "-37.3159",
      "lng": "81.1496"
    }
  },
  "phone": "1-770-736-8031 x56442",
  "website": "hildegard.org",
  "company": {
    "name": "Romaguera-Crona",
    "catchPhrase": "Multi-layered client-server neural-net",
    "bs": "harness real-time e-markets"
  }
}
2 As For Each iterates over each object, the DataWeave expression (payload.company) in the Transform component (<ee:transform />) uses DataWeave selectors to extract the value of each "company" key and transform the payload to the value of each of those keys. As in a Mule flow, the next component within For Each receives the transformed payload as its input.
3 The File Write operation (<file:write />) uses payload.name within a larger DataWeave expression to select the name of each company from the transformed object. The name of each file follows the pattern specified in the expression, which hyphenates the extracted company name and appends a date-time stamp to make the file name unique. For example, the name of a file for Romaguera-Crona data looks like this:
Romaguera-Crona-20221007113314.json

By default, the operation also loads the payload received from Transform Message to each file.

4 The logs print the following message for the first object from the input array:
{
  "name": "Romaguera-Crona",
  "catchPhrase": "Multi-layered client-server neural-net",
  "bs": "harness real-time e-markets"
}

When processing Mule variables, execution within For Each begins with the values of Mule variables from the previous execution. New Mule variables or modifications to the values of existing variables that take place when processing one element are accessible during the processing other elements. Changes to Mule variables continue to be available outside the For Each scope.

<set-variable variableName="var1" value="var1-BeforeForEach"/>
<set-variable variableName="var2" value="var2-BeforeForEach"/>
<foreach collection="#[['apple', 'banana', 'orange']]">
    <choice>
        <when expression="#[payload == 'apple']">
            <set-variable variableName="var2" value="var2-newValue"/>
            <set-variable variableName="var3" value="var3-appleVal"/>
        </when>
        <when expression="#[payload == 'banana']">
            <set-variable variableName="var3" value="#[vars.var3 ++ ' bananaVal']"/>
            <!-- var3 will now have value 'var3-appleVal bananaVal'-->
        </when>
        <otherwise>
            <set-variable variableName="var3" value="var3-otherVal"/>
            <set-variable variableName="var4" value="var4-val4"/>
        </otherwise>
    </choice>
    <logger level="INFO" doc:name="Logger After Choice"
            message='#[ [vars.var1, vars.var2, vars.var3, vars.var4] as Array ]'/>
</foreach>
<logger level="INFO" doc:name="Logger After For Each"
         message='#[[vars.var1, vars.var2, vars.var3, vars.var4] as Array]'/>

As the Choice router (<choice />) executes the processors within each condition, the Logger (Logger After Choice) prints the following variable values:

// Condition: when payload == 'apple'
.LoggerMessageProcessor:
[var1-BeforeForEach, var2-newValue, var3-appleVal, null]

// Condition: when payload == 'banana'
.LoggerMessageProcessor:
[var1-BeforeForEach, var2-newValue, var3-appleVal bananaVal, null]

// Condition: otherwise
.LoggerMessageProcessor:
[var1-BeforeForEach, var2-newValue, var3-otherVal, var4-val4]

The last values are propagated outside of For Each. The logger (Logger After For Each) prints the same values as the ones printed after the final choice condition (otherwise).

[var1-BeforeForEach, var2-newValue, var3-otherVal, var4-val4]