Group by Path
LAST UPDATED: JUNE 18, 2025
The Merge task’s "groupBy": "Path"
configuration enables merging by resolving one or more specified path expressions within upstream task outputs. For each successful path resolution, the entire execution lineage contributing to that match is merged into a separate result object.
Merge Condition Format
To apply this configuration, the merge condition must include at least the following two keys:
{
"groupBy": "Path",
"paths": [
"$['<node1>'].<path>",
"$['<node2>'].<path>",
"$['<node3>'].<path>",
"$['<nodeN>'].<path>"
]
}
Core Concepts
The examples below demonstrate how variations in task structure, path specification, and output availability influence merge.
OBJECTIVE – Learn what data fields are returned when using groupBy: "Path"
and specifying the return data path of a task node in a single linear execution stream.
Build the following playbook:
Configure task A1 to return "A1", task A2 to return "A2", and task A3 to return "A3".
Input the following merge condition:
JSON{ "groupBy": "Path", "paths": ["$['A1'].returnData"] }
Test run the playbook.
Observe the execution results for the Merge task in the Raw Data tab.
Repeat steps 3-5 changing the paths key in the Condition parameter to reference different task nodes (i.e., A1, A2, and A3).
TAKEAWAYS
Regardless of which task is specified in the paths key, if a match is found, the entire execution lineage—DataSource, A1, A2, and A3 in this case—is consolidated into an object within the merge result.
OBJECTIVE – Contrast the merge execution outputs for matched and unmatched paths.
Build the following playbook:
Configure task A1 to return "A1", task A2 to return "A2", and task A3 to return "A3".
Configure task B1 to return "B1", task B2 to return "B2", and task B3 to return "B3".
Input the following merge condition:
JSON{ "groupBy": "Path", "paths": ["$['B1'].returnData"] }
Test run the playbook.
Observe that two execution instances of the Merge task are present.
READER NOTE
The number of executions, indicated by the icon, reflects the count of completed tasks that provide input via connecting arrows.
Observe the execution results for the Merge task in the Raw Data tab.
Observe the execution results for the other instance.
TAKEAWAY
The Raw Data tab, containing the merge results, renders only for execution instances that match the Merge condition.
OBJECTIVE – Learn how the paths
key affects merge results when parallel branches share a common ancestor node.
Build the following playbook:
Input the following merge condition:
JSON{ "groupBy": "Path", "paths": ["$['1'].returnData"] }
Test run the playbook.
Click on the
icon within the Merge node.
Observe the execution results for the Merge task in the Raw Data tab.
MERGE RESULTJSON[ { "DataSource": { ... }, "1": { ... }, "2.2": { ... }, "Merge": { ... } }, { "DataSource": { ... }, "1": { ... }, "2.1": { ... }, "3": { ... } } ]
Stop the test, then repeat steps 2-5 using the paths key ["$['2.1'].returnData"] or ["$['3'].returnData"].
MERGE RESULTJSON[ { "DataSource": { ... }, "1": { ... }, "2.1": { ... }, "3": { ... } } ]
Stop the test, then repeat steps 2-5 using the paths key ["$['2.2'].returnData"].
MERGE RESULTJSON[ { "DataSource": { ... }, "1": { ... }, "2.2": { ... }, "Merge": { ... } } ]
OBJECTIVE – Compare grouping by an Unwind task's contextData path versus the returnData paths of its downstream tasks.
Build the following playbook:
Input the following JSON data for the Unwind A task:
JSON[ { "demoKey1": "value1", "demoKey2": "value2" }, { "demoKey3": "value3", "demoKey4": "value4" }, { "demoKey5": "value5", "demoKey6": "value6" } ]
Configure task B1 to return the following:
JSON[ { "demoKey7": "value7", "demoKey8": "value8" }, { "demoKey9": "value9", "demoKey10": "value10" }, { "demoKey11": "value11", "demoKey12": "value12" } ]
Input the following dynamic JSON Data parameter for the Unwind B task:
JSON{{ $.PlaybookData.B1.returnData }}
Configure task A2 to return "A2", task task B3 to return "B3", and task AB to return "AB".
Select and configure a Delay system utility command task with a 5 second duration.
Input the following merge condition:
JSON{ "groupBy": "Path", "paths": ["$.['Unwind A'].contextData"] }
Test run the playbook.
Click on the
icon within the Merge node.
Locate execution instances with the Raw Data tab visible, then review the execution result.
MERGE RESULT 1JSON[ { "DataSource": { ... }, "Unwind A": { ... }, "A2": { ... }, "AB": { ... }, "Merge": { ... } } ]
MERGE RESULT 2
JSON[ { "DataSource": { ... }, "Unwind A": { ... }, "A2": { ... }, "AB": { ... }, "Merge": { ... } } ]
MERGE RESULT 3
JSON[ { "DataSource": { ... }, "Unwind A": { ... }, "A2": { ... }, "AB": { ... }, "Merge": { ... } } ]
Stop the test, then repeat steps 8-10 using the paths key ["$.['A2'].returnData"].
MERGE RESULTJSON[ { "DataSource": { ... }, "Unwind A": { ... }, "A2": { ... }, "AB": { ... }, "Merge": { ... } }, { "DataSource": { ... }, "Unwind A": { ... }, "A2": { ... }, "AB": { ... }, "Merge": { ... } }, { "DataSource": { ... }, "Unwind A": { ... }, "A2": { ... }, "AB": { ... }, "Merge": { ... } } ]
Stop the test, then repeat steps 8-10 using the paths key ["$.['Unwind B'].contextData"].
MERGE RESULT 1JSON[ { "DataSource": { ... }, "B1": { ... }, "Unwind B": { ... }, "B3": { ... }, "Delay 5 Seconds": { ... }, "AB": { ... } } ]
MERGE RESULT 2
JSON[ { "DataSource": { ... }, "B1": { ... }, "Unwind B": { ... }, "B3": { ... }, "Delay 5 Seconds": { ... }, "AB": { ... }, "Merge": { ... } } ]
MERGE RESULT 3
JSON[ { "DataSource": { ... }, "B1": { ... }, "Unwind B": { ... }, "B3": { ... }, "Delay 5 Seconds": { ... }, "AB": { ... }, "Merge": { ... } } ]
Stop the test, then repeat steps 8-10 using the paths key ["$.['B3'].returnData"].
MERGE RESULTJSON[ { "DataSource": { ... }, "B1": { ... }, "Unwind B": { ... }, "B3": { ... }, "Delay 5 Seconds": { ... }, "AB": { ... }, "Merge": { ... } }, { "DataSource": { ... }, "B1": { ... }, "Unwind B": { ... }, "B3": { ... }, "Delay 5 Seconds": { ... }, "AB": { ... }, "Merge": { ... } }, { "DataSource": { ... }, "B1": { ... }, "Unwind B": { ... }, "B3": { ... }, "Delay 5 Seconds": { ... }, "AB": { ... } } ]
Stop the test, then repeat steps 8-10 using the paths key ["$.['AB'].returnData"].
MERGE RESULTJSON[ { "DataSource": { ... }, "Unwind A": { ... }, "A2": { ... }, "AB": { ... }, "Merge": { ... } }, { "DataSource": { ... }, "Unwind A": { ... }, "A2": { ... }, "AB": { ... }, "Merge": { ... } }, { "DataSource": { ... }, "Unwind A": { ... }, "A2": { ... }, "AB": { ... }, "Merge": { ... } }, { "DataSource": { ... }, "B1": { ... }, "Unwind B": { ... }, "B3": { ... }, "Delay 5 Seconds": { ... }, "AB": { ... }, "Merge": { ... } }, { "DataSource": { ... }, "B1": { ... }, "Unwind B": { ... }, "B3": { ... }, "Delay 5 Seconds": { ... }, "AB": { ... }, "Merge": { ... } }, { "DataSource": { ... }, "B1": { ... }, "Unwind B": { ... }, "B3": { ... }, "Delay 5 Seconds": { ... }, "AB": { ... }, "Merge": { ... } } ]
TAKEAWAYS
Grouping by the contextData path of an Unwind task produces one merge result per deconstructed item.
Grouping by subsequent tasks' returnData, even when multiple execution instances exist, yields a single merge result.
OBJECTIVE – Demonstrate the use of multiple paths for the merge condition, and the impact of a missing path on the resulting merged output.
Build the following playbook:
Input the following merge condition:
JSON{ "groupBy": "Path", "paths": [ "$.['A2.1'].returnData", "$.['B1'].returnData" ] }
Test run the playbook.
Click on the
icon within the Merge node.
Verify that two execution instances of the Merge task display a Raw Data tab containing an array.
MERGE RESULT 1JSON[ { "DataSource": { ... }, "B1": { ... }, "Merge": { ... } } ]
MERGE RESULT 2
JSON[ { "DataSource": { ... }, "A1": { ... }, "A2.1": { ... }, "Merge": { ... } } ]
Stop the test, then repeat steps 2-5 using the following merge condition:
JSON{ "groupBy": "Path", "paths": [ "$.['A2.1'].returnData", "$.['B1'].contextData" ] }
MERGE RESULTJSON[ { "DataSource": { ... }, "A1": { ... }, "A2.1": { ... }, "Merge": { ... } } ]
Because task node B1 does not include a contextData path in its output, only one merge result is generated.
Stop the test, then repeat steps 2-5 using the following merge condition:
JSON{ "groupBy": "Path", "paths": [ "$.['B1'].returnData", "$.['B2.1'].returnData" ] }
MERGE RESULT 1
JSON[ { "DataSource": { ... }, "B1": { ... }, "B2.2": { ... } } ]
MERGE RESULT 2
JSON[ { "DataSource": { ... }, "B1": { ... }, "B2.1": { ... }, "Merge": { ... } } ]
TAKEAWAY
Each path specified in the merge condition that resolves to a value contributes an output array to a separate merge instance.
OBJECTIVE – Illustrate how the number of merge results reflects the number of downstream executions.
Build the following playbook:
Configure task D to return "D".
Input the following merge condition:
JSON{ "groupBy": "Path", "paths": ["$['D'].returnData"] }
Test run the playbook.
Note that the task positioned downstream of the Merge task executes a single time.
Build the following playbook:
Configure task C to return "C".
Input the following merge condition:
JSON{ "groupBy": "Path", "paths": [ "$['Unwind A'].contextData", "$['Unwind B'].contextData" ] }
Test run the playbook.
Note that the task positioned downstream of the Merge task executes six times.
Input the following merge condition:
JSON{ "groupBy": "Path", "paths": [ "$['Unwind A'].contextData", "$['Unwind B'].contextData", "$['C'].returnData" ] }
Test run the playbook.
Note that the task positioned downstream of the Merge task executes seven times.
TAKEAWAY
The number of downstream executions, following the Merge task, has a 1:1 correspondence with the number of Merge task executions that have produced a result.
FAQ
OBJECTIVE – Learn how to configure the merge condition to point to a nested path.
Build the following playbook:
Configure task A to return the following:
JSON[ { "layer1": { "layer2": [ { "layer3": { "layer4": { "layer5": { "values": [ { "id": 1, "data": ["1", "11", "111"] }, { "id": 2, "data": ["2"] }, { "id": 3, "data": ["3", "33", "333"] } ] } } } }, { "layer3": { "layer4": { "layer5": { "values": [ { "id": 4, "data": ["4", "44", "444"] }, { "id": 5, "data": ["5", "55", "555"] }, { "id": 6, "data": ["6", "66", "666"] } ] } } } } ] } } ]
TARGET – Task A: Check for the presence of a second element in the "data" array within the second object of a nested "values" array.
The merge condition's paths
key supports the recursive descent operator (..).
Input the merge condition:
JSON{ "groupBy": "Path", "taskName": "A", "paths": [ "$['A']..values[1].data[1]" ] }
Test run the playbook.
Click on the
icon within the Merge node.
Observe the merge result in the Raw Data tab.
MERGE RESULTJSON[ { "DataSource": { ... }, "A": { ... }, "Merge": { ... } } ]
READER NOTE *
The second "layer2" element includes a nested "values" array whose second object contains a "data" array with a second element.

TARGET – Task A: Check for the presence of a second element in the "data" array of all nested "value" objects where the id equals 5.
Repeat steps 3-6 with using the following merge condition:
JSON{ "groupBy": "Path", "paths": [ "$['A']..values[?(@.id==5)].data[1]" ] }
MERGE RESULT
JSON[ { "DataSource": { ... }, "A": { ... }, "Merge": { ... } } ]
MERGE CONDITION EXPLANATION *
The filter ?(@.id==5) selects an object within "values" arrays where the "id" specifically equals 5. The subsequent .data[1] accesses the second element of the "data" array within that same object.
TARGET – Task A: Check for the presence of a second element in any "data" array.
Repeat steps 3-6 with using the following merge condition:
JSON{ "groupBy": "Path", "paths": [ "$['A']..data[1]" ] }
MERGE RESULT
JSON[ { "DataSource": { ... }, "A": { ... }, "Merge": { ... } } ]
MERGE CONDITION EXPLANATION *
This merge condition checks for the presence of a second element in any "data" array located at any depth.