Admins / Developers / DevOps

The Scalable Way to Create Roll-Up Summaries Using Salesforce Flow

By Nate Strong

Roll-ups, as we all know, are an extremely powerful tool inside Salesforce. However, Salesforce’s out-of-the-box functionality only supports roll-ups in a master-detail relationship. Master-details, while helpful in certain scenarios, can also bring limitations in most desired relationships between two objects.

We’re going to discuss the various options for expanding the functionality of roll-ups, as well as how to create an invocable action in flows to run a roll-up summary declaratively – even if there is no lookup relationship between the two objects.

Roll-Up Summary Fields in Salesforce

The default roll-up summary fields are some of the first things that new Salesforce Admins learn. However, due to the drawbacks mentioned above, there have been several attempts to bring this power to standard lookup relationships, not just master-details.

Enter many tools, such as the open-source Declarative Lookup Roll-Up Summaries and the more productized Roll-Up Helper. These allow you to declaratively roll-up fields between two related objects with custom filters. All of these roll-up tools create even more power for admins and users.

However, three big drawbacks remain with all roll-up tools – the first is flexibility. With DLRS you can almost write your own SOQL, but you’re not able to fully customize the whole query. The second is that there must be a relationship between the two objects to do the roll-up inside these tools. The third is that you have to execute the roll-up in a separate transaction after you save the record, so the roll-up executes independent of any automations.

A lot of this came to a head at Strong CRM when we were creating complex quota management systems inside Salesforce. We didn’t want to create multiple lookup relationships for various quota types (Company, Manager, User, SDR, etc.), and we wanted the roll-up to execute in a specific order inside the flow so that we could roll-up from Fiscal Quarter to Fiscal Year quotas.

So, we wrote an invocable action that allows you to write custom SOQL inside a formula resource in a flow – executing that SOQL, and sending back the aggregate result to a variable. This invocable action creates a new way to do declarative roll-ups, and by the nature of being invocable, can be triggered when you want it inside of any flow. We’ve now expanded its use beyond Quota Management and have started using it in all flows.

Create an Invocable Action to Complete Roll-Ups Within a Flow

Here’s how it works:

1. Create a Flow and New Action

Inside a flow, create a new action and select Custom SOQL Query:

In the queryString box, create a new Formula resource. This is where you write your SOQL. The raw text output of the formula will need to be the exact SOQL query. Also, this is built to only spit out one number, so make sure the query is:

  • An aggregate function
  • Gives a number back
  • Gives only one variable back

Put all the SOQL query items in quotes, close the quotes and add the ‘&’s to add in variables, and then reopen the quotes for more text.

Here’s an example of a correct SOQL Query:

Back in the Action Menu, open the Advanced dropdown, check Manually Assign Variables and assign the variable that the result should go to:

Make sure that this result variable is available for input and output since it will be used outside of the flow.

Click Done. And that’s it – the query will run in the flow when requested, and it will spit out the aggregate number when done. You can do this as many times as you like inside the flow (as long as it doesn’t hit Salesforce’s limits) with as much SOQL as you want to write in that box, as long as each query only returns one number.

2. Create a New Apex Class

To Install: In the Developer Console in a Sandbox, create a new Apex Class for the Custom SOQL Query invocable action. Call it CustomSOQLQuery.apxc.

global class CustomSOQLQuery {
	@InvocableMethod (label = 'Custom SOQL Query')
    global static List<Decimal> customQueries(List<QueryRequest> requests) {
        List<Decimal> results = new List<Decimal>();
        //loop through list of requests
        for (QueryRequest request : requests) {
      		results.add(customQuery(request));
    	}
        return results;
    }
	
    //actual work happens inside this method
    public static Decimal customQuery(QueryRequest request) {
        System.assert(request.queryString != '');
        
        List<AggregateResult> result = Database.query(request.queryString);
        
        Decimal sumAmount = 0;
        for (AggregateResult ar : result) {
			sumAmount = (Decimal)ar.get('expr0');
        }
        
        return sumAmount;
    }
    
    //custom class for input
    global class QueryRequest {
        @InvocableVariable(required=true)
        public String queryString;
    }
}

3. Create a Test Class

Then you’ll need a test class. Here’s one we’ve written for this:

@isTest
public class CustomSOQLQueryTest {
	@isTest
    private static void customQueryTest() {
        List<CustomSOQLQuery.QueryRequest> requests = new List<CustomSOQLQuery.QueryRequest>();
    	CustomSOQLQuery.QueryRequest request = new CustomSOQLQuery.QueryRequest();
        
        String testQuery = 'SELECT SUM(Amount) FROM Opportunity WHERE Id='0068c00000rTePSAA0'';
        request.queryString = testQuery;
        requests.add(request);
        
        CustomSOQLQuery.customQueries(requests);
        Decimal summedField = CustomSOQLQuery.customQuery(request);
    }
}

For the highlighted ID, make sure it’s an ID from an Opportunity in your dev instance. Run the test to ensure 100% code coverage (the test should give you 100%) and then deploy it to production.

Summary

There you go — you can now run fully custom declarative SOQL Queries inside flows, rolling up whatever data you like!

What has been your experience so far? Let us know in the comments.

READ MORE: Create Roll-up Summary Fields Using Salesforce Flow

The Author

Nate Strong

Nate Strong is a former VP of Sales, CRO, and is currently the CEO of Strong CRM, a Salesforce Consultancy specializing in B2B SaaS, Wealth Management, Professional Services, and Healthcare Providers.

Leave a Reply

Comments:

    Nelson Rioux
    October 13, 2022 1:20 pm
    I had to do one last week. As an admin sho is not a programmer I prefer a solution that is 100% flow (no apex classes). My Flow was: - Extract ID - Get records - Loop on records - Decision - Assignmenta Sum field with a SUM function - Update the field I had to fix an issue. You have to put a Default value of "0" to the Sum field.
    Nic
    October 16, 2022 12:51 pm
    So could you roll this in with the "Execute SOQL Query" that is installed as part of https://unofficialsf.com/a-graphical-soql-query-builder-for-flow/ so no need to write any apex class / test class at all? Feel like I need to try this out thanks !! :)
    Jay Herrera
    October 18, 2022 4:42 pm
    Wouldn't this very quickly hit governor limits in situations where the flow is triggered regularly? For example if I wanted to count Contacts at an Account when new Contact is inserted, I could see this being a brick wall if someone imported a batch of contacts or even if it was scheduled.
    Juha Lassila
    October 27, 2022 1:48 am
    Looping records will hit the limit of 2000 executed elements when there are lots of records. See https://help.salesforce.com/s/articleView?id=000382258&type=1
    Matt Hammel
    October 30, 2022 8:02 pm
    I don't have Custom SOQL Query as an available option in the New Action field. In fact the types listed are different in my org than in your screen shot. Is this version specific?
    Hayley Tuller
    October 31, 2022 5:33 pm
    I feel like the instructions are backwards -- do you need to create the apex first?
    Petr
    December 02, 2022 8:38 am
    Ahh men thank you so much - that is exactly what i am looking for!
    RichT
    April 21, 2023 5:16 pm
    Nate, I would love if you could revise this article and include more detail to help Admins understand and implement it without having much developer knowledge.