Working with lists in Okta Workflows is common, but sometimes the list processing actions can be overwhelming and confusing. In this article I look at how I approached a problem of consolidating nested lists with a standard pattern of Lists actions. It should give you an idea of how you can use different Lists actions to achieve operations on complex lists.
The Problem
I needed to find a list of server objects that matched a search argument using APIs in Okta Workflows. There was no single API I could use to produce a filtered list of all servers in the environment, so I needed to drill down through various levels of objects to get to the objects I wanted. In this specific case (working with Okta Privileged Access) I needed to find a list of resource groups, and for each resource group I needed to find all projects, and for each project I needed to find all servers defined and then see if the found servers matched my search argument. This involved working with Lists in Okta Workflows.
There are many ways to process lists, including List – For Each, List – Map and List – Reduce. The For Each action wouldn’t return the data I needed and the Reduce action only returns a single value (see Learn the Differences Between Three Workflows List Functions: For Each, Map, and Reduce). The only option was the Map action, but using it I ended up with nested lists (three-deep) with empty objects (i.e. servers not found) possibly at each level. I had to come up with an approach to filter out the empty rows at each level and consolidate lists of lists into a single list.
Overview of the Solution
For this solution I had to drill down into multiple subflows to generate lists. In summary:
- At the top level flow I called an API to return a list of all Resource Groups. For each item in the Resource Group list, I called a subflow
- The first subflow used the Resource Group Id to call another API to return a list of Projects in the Resource Group. For each item in the Projects list, I called another subflow
- The second subflow used the Project Id to call another API to return a list of Servers in the Project. For each item in the Servers list, I called another subflow.
- The third (and last) subflow checked each server against a search argument and either returned an object for that server (if a match) or nothing (if not a match)
- The second subflow then returns the list of server objects in the project to the first subflow
- The second subflow used the Project Id to call another API to return a list of Servers in the Project. For each item in the Servers list, I called another subflow.
- The first subflow then returns the list of server objects in the projects in the resource group to the main flow
- The first subflow used the Resource Group Id to call another API to return a list of Projects in the Resource Group. For each item in the Projects list, I called another subflow
- The main flow then has a list of all matching server objects in the projects in the resource groups across the Okta PA team.
At each level (i.e. in the main flow, first subflow and second subflow) there needs to be actions to remove blanks and consolidate any nested lists so that the final list is just a single-level list of matching server objects.
The standard pattern I used for processing a list of lists at the different levels is shown below.

The steps are:
- First is a List – Map action to call a subflow (helper flow) to process each item in the list. This returns a list of results (objects) from the subflow, with the same number of items as was passed in.
- Next is a List – Filter action working on the returned flow to strip out the blank entries
- Then a List – Pluck action will pull out the objects by key and return just an object list
- Finally a List – Flatten action will consolidate the nested lists into a single list. If the called subflow (helper flow) is returning just an object rather than a list, then this step isn’t needed
Don’t worry if this doesn’t make sense, the following sections will explain with examples. The examples below are based on the first subflow, which has two levels of subflow below it, so will be returned a list of objects (that are lists themselves).
Step 1 – List-Map
The first step is to use a List – Map action to run a subflow across each item in a list. A Map action will return a list with exactly the same number of items passed into the list. The input and output formats can be different.
In the following example I’m passing in a list of id’s (text fields) and returning a list of objects. There are four items passed into the Map action and four items returned.

The called subflow will process each item and return a value. In this case the called subflow is making an API call using the id passed in, and the result is a nested list of server objects or blanks (empty lists) if nothing was found.
In this case, the item returned (called “found_server_list”) is an object that contains a list. This returned list may be empty or contain a list of objects. This is because the called flow is returning a list of objects (and the calling flow is receiving a list of objects). If you had returned a list of text, you would see just the server objects, but no “found_server_list” key – which we need this for the next step.
Step 2 – List-Filter
The second step is a List – Filter action to filter out any blank items from the list returned from the List – Map action.
The Filter action has an operator of is not empty on a path of found_server_list. This will only return non-empty items in the list.

You can see that the list passed into the Filter action has four items but two of them are empty ("found_server_list":[]). These are discarded to leave two items (which are two objects, one list with two server objects and one list with one server objects).
Step 3 – List-Pluck
The third step is a List – Pluck action to pluck out the found_server_objects and return just the objects within them. The Pluck function is to pull every item in objects in a list that match the specified key.

In this case there are two objects with a key of found_server_object and the result is two lists with three server objects (two in the first list, one in the second).
Step 4 – List-Flatten
The last step is a List – Flatten action to reduce a list of lists to a single list.

In this case, the two lists of servers within the one top-level list, is consolidated into a single list of the three server objects.
This is the final list as this is a subflow the list is passed up to the next level and filtered/consolidated again until the main flow has a single list of objects representing the servers that match the query.
Conclusion
This article has shown how a combination of List actions can be used to consolidate a multi-layered lists of lists. It showed how the List – Map, List – Filter, List – Pluck and List – Flatten cards can be used together to filter out empty entries and produce a single-level list of objects, no matter how deep the list nesting is.
This article should give you enough detail so you can go try this yourself and understand how the different actions can be used and how to process complex lists of lists.

IAMSE