How To

Let’s Get With The Flow – Loop Basics

LoopdeLoop

Ever have an automation use case where you need to take a collection of records and do something with them? The only declarative (clicks, not code) automation tool that can stand up to the task is Flow Builder.

As someone who identifies with an Admin, I have to admit, it took me a while to understand how to configure loops in flow.  I hope these basic steps help you in understanding how to configure a basic loop.

Here are a few lessons learned from implementing this use case:

  • Learn how to create a loop, set values via assignments, add a loop record to a collection and handle DML (database actions) outside of the loop.
  • Provide descriptions, where provided, in Salesforce. This may be tedious step, I know, but your future self will thank you when you are trying to remember what you configured or assist other/future admins when troubleshooting or enhancing what was built. This includes variables, the purpose of a flow, what each flow element does, etc.

What’s a loop? Think of it as an assembly line. Every item going down the assembly line has the same actions taken on it. In the Salesforce world, if you have a group of records that you need to perform the same actions on for every record in this grouping would go through a loop. Each record, when it is its turn to go down the assembly line will be placed into a record variable, in my case, I call varLoopRecord. After it’s done with its turn, then that record is removed from varLoopRecord and the next record is stored in varLoopRecord. This continues to happen until we are done with the last record in the collection and therefore, ends the loop.

ILoveLucyAssemblyLine.gif

Start a loop path, iterating through the records in a collection variable. For each iteration, the flow temporarily stores the record in the loop variable (in my example, varLoopRecord). Often times, within a loop, you would want to make decisions and set certain values to fields in the loop record.

A collection variable is a list of records you wish to take action on. A loop uses a loop variable to store the values for the current record in the collection. When the loop completes taking action on the one loop record, Salesforce then places the next record into the loop variable. To keep track of changes made along the loop path, add the loop record variable as a record to a new collection variable.

One very important note: Avoid the bad Apex development practice of making a DML operation within a loop. You do not want to hit Salesforce-imposed ‘governor’ limits on how many database operations you can do in a single transaction. This same limit applies to flows as well.

Business Use Case:  Addison Dogster is the system administrator at Universal Containers. Mary Markle is the Director of Operations. She would like to automatically update cases with a status of Escalated to a High priority and set the IsEscalated checkbox to true.

Solution: This blog post will just cover solution of getting the group of cases that have the Escalated status and taking action on those records.

The outcome looks like this:

FlowWithaLoop

This flow does the following: (1) get the cases where the status is set to Escalated and store the records in a collection, (2) a decision to determine whether records were found in the query, (3) put each record in a loop record variable, (4) set the priority to “High” and the IsEscalated checkbox to true, (5) add the loop record variable into a new collection of records that will be updated and after the last record in the collection is completed, (6) update the records in the new collection.

Steps: 

1. Let’s create the flow. For those using Salesforce Classic, flow can be found in Create | Workflows & Approvals | Flows. In Lightning Experience, it is found under Process Automation | Flows. Select to create an Autolaunched flow.

A. Let’s create our flow resources.

Best practice tip: Provide a description so you and other/future admins know what this flow resource is used for.

Create a record collection variable resource called “CollectionToBeUpdated” that has a record data type, Case as the object and is set to allow multiple values (collection).

CollectionToBeUpdated.PNG

B. Next, we will use Get Records flow element to query the Case object to get all the records with the status of Escalated.

Object: Case

Filter the Case Records by Status Equals Escalated.

How many records to store: All records

For the “How to Store the Data” option, I chose to use “Automatically store all fields.”

Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.

FlowWithaLoop-GetCasesView image full screen

C. We will a Decision flow element to determine whether records were found in the previous step. If not records were found, the flow would fault when it get to the step in the flow where it tries to do things with the loop record variable — there is no record to work with!

Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.

For the “Records Found” outcome, we need to check record collection has items. Set the conditions to the following:

{!Get_Cases} Is Null {!GlobalConstant.False} (This is a double negative. Which means, there is at least one record in the collection).

The default outcome: No Records

FlowWithaLoop-DecisionView image full screen

D. We now need a Loop flow element where we will take each record in the Get Cases record collection variable to iterate through. Configure it as follows:

Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.

Collection Variable :{!Get_Cases}

FlowWithaLoop-LoopView image full screen

E. For a loop record variable, we need an Assignment flow element to assign values to fields that we will update in this flow. We will assign “High” as the priority and true to the IsEscalated checkbox field in the Loop record variable. Configure it as follows:

Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.

Set the variable values to:

{!Loop.Priority} Equals High

{!Loop.IsEscalated} Equals {!GlobalConstant.True}

FlowWithaLoop-AssignmentView Image Full Screen

F. We need another Assignment flow element to assign the loop record {!Loop} to a new collection (!CollectionToBeUpdated} that will be updated after the loop ends.

I have to admit, this configuration trips me up. It reads backwards AND you don’t need to specify the Id of the loop record variable, just specify the loop record variable. Here we are added the {!Loop} to the collection {!CollectionToBeUpdated).

Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.

Set the variable values to:

(!CollectionToBeUpdated} Add {!Loop}

As noted earlier, but worth noting again, please avoid database actions within a loop. Close the loop and make your DML action outside the loop to avoid hitting Salesforce governor limit for the number of DML actions within a transaction.

FlowWithaLoop-AssignmentAddtoCollectionView Image Full Screen

G. Now that we’ve closed the loop, we want to update all the records in the collection (!CollectionToBeUpdated} with an Update Records flow element. This will update the priority to “High” and IsEscalated to true for all records in the collection.

Configure it as follows:

How to Find Records to Update and Set Their Values: Use the IDs and all field values from a record or record collection

Record or Record Collection: {!CollectionToBeUpdated}

FlowWithaLoop-UpdateRecords.PNG

View image full screen

H. Add the subflow Send Flow Fault Email. For instructions on how to create this, go to Step 2 of blog post: Maximize Maintainability With Process Builder and Componentized Visual Workflow. Set your flow starting point. And connect the flow elements, fault connectors and outcome connectors to match the below…

FlowWithaLoop-Connectors

I. Save/Save As and provide the following properties.

Best practice tip: Provide a description so you and other/future admins know what this flow is used for.

FlowWithaLoop-Properties.PNG

View image full screen

I. Click the “Activate” button.

Note: This flow can be set as a scheduled flow or invoked by a process or invoked by a button. The initiation will not be covered in this blog post.

Now, before you deploy the changes to Production, don’t forget to test your configuration changes.

  1. Create a few cases with the status of Escalated with a priority that is not set to High and IsEscalated is unchecked.
  2. Initiate the flow.
  3. Verify the cases were updated (priority is now set to High and the IsEscalated checkbox is now set).

Deployment Notes/Tips:

  • Flow can be deployed to Production in a change set (or can be deployed using a tool such as Metazoa’s Snapshot).
  • You will find flow in a change set under the Flow Definition component type.
  • Activate the flow post deployment as flows deploy inactive in Production, unless you have opted in on the Process Automation Settings screen, to “Deploy processes and flows as active.” NOTE: With this change, in order to successfully deploy a process or flow, your org’s Apex tests must launch at least 75% of the total number of active processes and active autolaunched flows in your org.

34 thoughts on “Let’s Get With The Flow – Loop Basics

  1. Thanks Jen! I don’t work with Flows as often as I’d like, but when I do, I feel like I end up having to spend half a day getting my head wrapped back around Loops. This will be a great reference for me in the future!

    Like

  2. Hi Jen, this is an extremely helpful look at Loops in Flow. I will admit, I have a really hard time wrapping my head around Flow, in general. Currently, I’m building one that looks at a collection of custom object records and has to update or create a new record based on a field from a related record collected earlier.
    I’m stuck on how to implement in a loop without a second decision point before the loop and assignment comes into play. Does that make sense at all? Any tips? Thanks again!

    Like

  3. This is super helpful, thank you! The one thing I still can’t figure out is how to update a field on a related object. How would you modify this flow if the fields you wanted to update were on an account object related to the case?

    Like

  4. A topic for a future blog post! You assign values to an account variable. Add the account to the collection variable of accounts to be updated once outside the loop. Then, you do an update records flow element with that collection variable.

    Liked by 1 person

  5. Thanks so much! This was awesome. As someone who is new to flows, loops throw me a bit, lots of things don’t seem to make sense, but you really broke it down in an easy fashion. As a Non Profit Admin, this was super helpful! thanks again!

    Like

  6. Is the Decision step really necessary? If Get Records returns a collection of 0, is the loop smart enough to never execute?

    Like

  7. No, your flow will fault if your next step is to take action on the collection and there are no items. Same deal with code. The code and flow does what you tell it.

    Like

  8. This is EXTREMELY helpful! Thank you. In fact, this is the second blog of yours that I’ve used in the past week that has helped me get a Flow working. You’re awesome!!!

    Like

  9. I finally got a business use case to build a Flow that needed a Loop and this helped a ton! Thanks! I did run into a hiccup with the Loop Variable since it is no longer needed (Summer 20) but ultimately found out what I needed to do.

    Like

  10. Now that we have 5 choices when starting to create a Flow (and since we sadly cannot yet clone a Flow or start building a Flow without choosing one of the 5), and since you show at the end that you save it as an Autolaunched flow that can be “set as a scheduled flow or invoked by a process or invoked by a button”, it looks like we should start off by choosing “Autolaunched Flow” if we’re following along with your instructions?

    BTW, I’ve heard great things about your Flow instructions and have always enjoyed your release highlight posts. Thanks for your amazing contributions to the Salesforce community!

    Like

  11. Also, I think where you mention “Contacts” you mean “Cases”? Or am I misunderstanding something? (Thought I’d ask, in case my question also helps someone else.)

    Like

  12. Would love updated instructions regarding the Loop Variable no longer being needed. @Josh – what did you need to do?

    Like

  13. Hi Jen – This can be a private message!

    Thanks for your replies. I’m so sad because I’ve been trying to wrap my brain around Flows and I can’t even get the simple Flow in this blog post to work, despite your step by step instructions. I was getting this error when I debugged the Flow: {!CollectionToBeUpdated} = “[Case (No ID)]” on the second Assignment Element. Then I realized I had to change VarLoopRecord to just Loop. Now it’s passing that Element, but at the end, I’m getting “All records whose IDs are in {!CollectionToBeUpdated} are ready to be updated when the next screen, pause, or local action is executed or when the interview finishes.” I have not added the subflow “Send Flow Fault Email” – is that the problem? (The instructions for that are not in the current Flow Builder format, so I’m hesitant to try to tackle that.). The record is not being changed.

    (BTW, there are additional references to Contacts still in the post – I mention it only in the hopes that it will not confuse others – took me a minute to try to understand what this had to do with Contacts.)

    Thanks in advance for any help.

    Like

  14. It wasn’t being updated. But then I realized I also had to change the 1st Assignment from VarLoopRecord to just Loop (“Current Item from Loop Loop”) (previously, I had only changed it in the 2nd Assignment) and now it works – huzzah! Thanks for your help!

    Like

  15. Great. Yes, I had to change varLoopRecord to just Loop since the loop variable is no longer available for new flows but is still there if you created a flow with your own loop variable.

    Like

  16. Hi! thanks very much for this tuto! I find myself in a difficult situation as I understand how you came up with your flow, but can’t figure out how to apply in my current situation.
    I use a flow to create some quote, and I have 2 custom objects related to it (I call Phase and Task). So before my quote is created I would like to ask the user how many phases he has for the quote, and for each quote, how many tasks and after all be able to fill out the phase number, phase name, task number and task name. Could you please help me with that (just to have an idea on how to start)?

    Like

  17. Jen,

    I’ve always referred to your guide template whenever I do flows… and I’ve done a few over the years in my ORG, but I have (2) questions hopefully you can help me understand….

    (1) In your first assignment, you put the Loop function as your Variable and your singleVarRecord as the value however I just found out it’s possible to set those assignments vice versa (by that I mean, setting the singleVarRecord as the variable and the Loop and the value– is there one method that is better recommended over the other or is either way okay?

    (2) I know the recommendation and best practice is that we do not perform actions within the loop however I have a use case where I’m looping over a series of Product2 records to update some cost value and sometimes the same product appears twice during loop/assignment– the flow ends up faulting because, I guess, collectionVar doesn’t like that I am editing the same Product2 record twice within my flow on mass update.. so would this be a reasonable justification for breaking that rule of thumb with no ‘actions within loop’?

    Thank a million if you ever reply to this… I know you’ve got tons of people probably firing off Qs to ya

    Like

  18. Hi DJ,

    (1) It depends what you are assigning. In my case, I am changing the values of my loop record. But in another case, I may be setting field values of a new variable record to specific using a value from a different variable. It really depends on what you are assigning rather than a recommended method.

    (2) While not recommended, I’ve done a DML action (Get Records) within a loop but only in the cases where I know for sure that I’m not dealing with so many records that I will run into governor limits.

    Hope that helps!
    Jen

    Like

  19. Hi Jen, thx for your clear explanation
    just what I needed to get my loopy flow working. much appreciated

    Like

Comments are closed.