Maps in Flow

by Aidan Harding - December 14, 2021
Maps in Flow

Maps are a fundamental data structure in Apex and other programming languages. They allow us to store a series of key/value pairs, and then efficiently use a key to look up a value from the store. There is no built-in map construct in Flow, but it would be useful if there were. So, I built one!

In this article, we find out about maps in general, show a use-case for them in Flow, and provide code that you can download today to use maps in Flow. If you are unfamiliar with Flows in general or just want a deep dive into them from a developer’s perspective, I wrote a deep dive into them in a previous post.

So, if you’re ready to get rid of super-wide decision nodes in your Flows, then read on…

What is a map?

A map is a series of key/value pairs. For example, you could use a map to store price information:

Key Value
Soup £1.00
Bread £1.50

Then, we could use the key “Soup” to get the corresponding value, £1.00. Behind the scenes, the data is organised carefully so that looking up a key does not require scanning through the entire table.

Why do developers love maps?

Because reading values from them is so fast! And they allow us to write Apex code that can run well on many records at once.

For example, in a trigger on Contact, our code must be ready to handle a list of Contacts. We may also need to refer to the Accounts related to those Contacts. In good Apex, we would query all the related Accounts at once, and then put them into a map where the keys are the Account record ids. Then, when we loop through the Contacts, we can quickly pull up the corresponding Account e.g.

public void handleAfterInsert(List<Contact> newList) {
    Set<Id> accountIds = new Set<Id>();
    
    for(Contact thisContact : newList) {
        accountIds.add(thisContact.AccountId);
    }
    
    Map<Id, Account> idToAccount = new Map<Id, Account>([SELECT Id, Name FROM Account WHERE Id IN :accountIds]);
    
    for(Contact thisContact : newList) {
        Account thisAccount = idToAccount.get(thisContact.AccountId);
        /* Now do some processing with the Contact and Account */
    }
}

ContactTrigger.cls

So, why didn’t Salesforce include maps in Flow?

Record-triggered Flows actually solve the scenario above about Contacts and Accounts without you having to create a map for yourself.

If you write a triggered Flow on Contact, you can use a “Get Records” node to query the Accounts related to all of the Contacts in the Flow trigger context. The Flow system itself makes sure that only one query is made to get all of the relevant Accounts. Then, the right Account record corresponding to the current Contact is just available for you in your Flow without you having to think about it.

It’s like Flow takes you straight inside the

/* Now do some processing with the Contact and Account */

part from the Apex code.

Time for a “Maps in Flow” use-case

Many Flows use a decision node to decide between branches containing many similar actions. For example, the decision could be on which Email Template to use, or which Record Type to use in creating a record. In many cases, this decision node with many branches could, instead, be handled by a single mapping operation.

For a concrete example, let’s suppose that we need a Flow to set the Record Type of Accounts as they are inserted. Each of the various values in Type will correspond to a Record Type

Type Record Type
Channel Partner / Reseller Channel_Partner
Customer – Channel Customer
Customer – Direct Customer
Installation Partner Partner
Technology Partner Partner
Other Other

We could write a Flow for that using a decision node as follows:

Branching Flow

The decision node assigns a different value to a variable, depending on the branch taken. The corresponding Record Type is then queried with “Get Records”, and finally assigned to the Account record.

And now with a Map in the Flow

This flow solves the same problem, but the decision node is replaced with a single “Map a Value” action:

Clearly, “Map Type to RecordType DeveloperName” is doing the heavy lifting, so let’s see how it is configured:

The configuration is in two parts.

  • First, we choose an input value: the Type field of the Account from the Flow trigger context.
  • Second, we set up the mapping, just as in the table above.

It’s that simple.

The only downside for this example is that because “Map a Value” is Apex, it can’t be used in a Before-Save/Fast Field Update Flow. This means that an extra node is required to write back to the Account.

In some cases, that might rule out this approach. But, if you are already writing an After-Save Flow, then this is not an issue. Also, Salesforce really should allow non-DML Apex Actions to run in Before-Save Flows.

How much (if at all) should I care about this?

You should always care about writing less code. Even if that code is nodes in a Flow rather than lines of Apex. By using Maps in Flow instead of decision nodes, you produce fewer nodes (less code) and that’s great by itself.

And there’s more… “Map a Value” clarifies the code that you have. When I read a Flow using a many-branched decision node, I assume that the decision branches are largely the same and the actions following from them are also largely the same. But this is just an assumption. It might not be true. There could be one weird decision branch that’s reading from some other fields. One action might be different from the rest.

These are the places where long and painful debugging sessions end up. With “Map a Value”, the conditions all have to be simple comparisons and there is only one action at the output. So it might not fit for the most complex situations, but there’s nowhere for nasty bugs to hide when it does fit.

We’re still not done… Part of the pitch for Salesforce is to have a system that can be quickly reconfigured to meet changing business needs. And Flow offers the promise of this. If the needs change, the Flow can change. But changing code carries risk. What if someone changes the wrong part of the Flow? The “Map a Value” node puts a piece of the configuration in an obvious place. You can change that table with much less risk than changing the logical structure of the Flow.

Source

Full source of the above examples and the “Map a Value” Apex Action are available on GitHub https://github.com/aidan-harding/flow-map. The source is MIT licenced, so you are free to use and modify it however you like.

The repo also contains a Custom Metadata-driven version of the same idea. It’s a little more intricate to set up, but it might work well in some cases. In particular, you can use that method from Before-Save Flows.

Feedback

As always, please do let me know what you think. Especially if you disagree or see any mistakes. Contact me on Twitter @AidanHarding or email aidan@nebulaconsulting.co.uk.

Related Content


Get In Touch

Whatever the size and sector of your business, we can help you to succeed throughout the customer journey, designing, creating and looking after the right CRM solution for your organisation