Advanced rollup calculations
Whilst the rollup() function allows the aggregation of measure property values the traverse() function returns a list of distinct results of a map across all descendants (inclusive)
The generic form for traverse() is:
node.traverse(map, reduce, finalize, options)
traverse returns the list of distinct results of the map across all descendants (inclusive) unless you choose to exclude self via the option {includeSelf: false}
map is a function that takes a node and returns an array.
reduce is a string: "distinctNodes"for a map that returns an array of nodes and "distinct" for a map that returns something else
finalize is optional and can often be left as undefined
options allows you to choose if you want to include the node referenced or not in the result
Distinct count of property valuesโ
To calculate the distinct count of departments of a nodes's descendants
Use traverse(map, reduce) and define the map function and reduce string.
We are interested in location so the map is:n => n.department
The result of the map isn't a node, so reduce is "distinct"
node.traverse(n => n.department, "distinct")

This is the list of distinct departments in the node's descendants
To count how many there are .count is added to the expression
node.traverse(n => n.department, "distinct").count

Distinct count of nodesโ
This example uses a people dataset and linked to an activity dataset
For a manager in the people dataset, you want to find the distinct leaf activities of its descendants
Then return the sum for activityFTE of those leaf activities
Use traverse(map, reduce) and define the map and the reduce
We are interested in leaf activities so the map is:
n => n.links.to.filter(n => n._is_leaf)
The result of the map is a node, so reduce is "distinctNodes"
node.traverse(n => n.links.to.filter(n => n._is_leaf), "distinctNodes")
The result is an array of nodes for the distinct leaf activities for the node's descendants

Each leaf activity is a node from the activity dataset
To view the labels for each of the nodes in the array .label can be added to the expression
node.traverse(n => n.links.to.filter(n => n._is_leaf), "distinctNodes").label

Finally to retrieve the activityFTE and sum the result add .activityFTE.sum to the expression
node.traverse(n => n.links.to.filter(n => n._is_leaf), "distinctNodes").activityfte.sum

Traverse excluding selfโ
By default traverse() includes the current node (itself)
If you want the expression to exclude the current node then you can add an argument to the traverse() to "exclude self"
This has the generic form:
node.traverse(map, reduce, finalize {includeSelf:false})
This example expression provides a distinct list of values for the department property and includes the current node
node.traverse(n => n.department, "distinct")

To exclude the currently selected node
node.traverse(n => n.department, "distinct", {includeSelf:false})

Traverse on filtered dataโ
If any filters applied to the dataset, traverse will perform calculations on the filtered subset of your data
node.traverse(n => n.department, "distinct")

To do traverse calculations on unfiltered data, use allTraverse() in the expression, instead of traverse()
node.allTraverse(n => n.department, "distinct")
