DEV Community

Victor Moura
Victor Moura

Posted on • Edited on

Salesforce Flow- Query records using List of Ids

This article can be considered obsolete. Since Winter '23, you can use IN/NOT IN operators on GET elements.


Intro

Fetching Records using a collection of Ids in Flow Builder should be a simple job, but somehow SF is still missing this ability. This limits the enforcing of best practices since sometimes we might have no choice but use GET elements inside a flow-loop.

The idea with this article is to show a simple implementation of an Apex Action to handle this limitation.

Basic Implementation

I'm assuming that the reader is already familiar with Invocable Methods/Variables and how to call Apex from a Flow.

That being said, we have this apex class that can solve our issue. Let's assume we want to fetch Contact records.

public with sharing class FlowQueryHelper{


    @InvocableMethod(label = 'GET Contacts where Ids in Collection')
    public static List<Output> getContactsInCollection(List<Input> params){
        String ids = params[0].ids;
        List<Contact> contacts = [
                SELECT Id, Name 
                FROM Contact 
                WHERE Id IN :ids];

        Output output = new Output();
        output.contacts = contacts;

        return new List<Output>{ output };
    }  

    public class Input{
        @InvocableVariable(label = 'Text collection variable (Ids only)' required = true)
        public List<String> ids;
    }

    public class Output{
        @InvocableVariable(label = 'Contacts Collection Variable')
        public List<Contact> contacts;
    }
}
Enter fullscreen mode Exit fullscreen mode

That works like a charm, but we can make it a little bit more generic in case we want to reutilize this class with other Object types and you probably will.

More Generic

Our class must be able to run for any custom or standard sObject. This means that it will be unaware of the sObject API Name and Fields in order to run for any collection of Ids we pass to it.

API Name

We can get the API Name directly from the Id by using describe methods. More details here.

    private static String getObjectName(String objId){
        return ((Id)objId).getSObjectType().getDescribe().getName();
    }
Enter fullscreen mode Exit fullscreen mode

Fields

Again we're making use of the well known Schema class and describe methods. More details here.

    private static String getObjectFields(String objectName) {
        List<String> fields = new List<String>(Schema.getGlobalDescribe().get(objectName).getDescribe().fields.getMap().keySet());
        return String.join(fields, ',');
    }    
Enter fullscreen mode Exit fullscreen mode

SOQL Query

And now we have the SOQL statement. We'll be using Dynamic SOQL to fetch our records. More details here.

Database.query('SELECT ' + String.escapeSingleQuotes(objectFields) + ' FROM ' + String.escapeSingleQuotes(objectName) + ' WHERE Id IN :ids')
Enter fullscreen mode Exit fullscreen mode

Final Version

public with sharing class FlowQueryHelper{


    @InvocableMethod(label = 'GET Records where Ids in Collection')
    public static List<Output> getRecordsInCollection(List<Input> params){

        String objectName = getObjectName(params[0].ids[0]);
        String objectFields = getObjectFields(objectName);
        List<String> ids = params[0].ids;

        List<sObject> records = Database.query('SELECT ' + String.escapeSingleQuotes(objectFields) + ' FROM ' + String.escapeSingleQuotes(objectName) + ' WHERE Id IN :ids');

        Output output = new Output();
        output.records = records;

        return new List<Output>{ output };
    }

    private static String getObjectName(String objId){
        return ((Id)objId).getSObjectType().getDescribe().getName();
    }

    private static String getObjectFields(String objectName) {
        List<String> fields = new List<String>(Schema.getGlobalDescribe().get(objectName).getDescribe().fields.getMap().keySet());
        return String.join(fields, ',');
    }

    public class Input{
        @InvocableVariable(label = 'Text Collection variable (Ids only)' required = true)
        public List<String> ids;
    }

    public class Output{
        @InvocableVariable(label = 'Record Collection Variable')
        public List<sObject> records;
    }
}
Enter fullscreen mode Exit fullscreen mode

And that's it, folks. Screenshot below as example for Account object.

Screenshot from Flow Builder screen showing new Custom Apex action with generic inputs and output

Conclusion

This will do the trick at least until SF comes up with a more final/solid solution. It's important to notice that when calling this action you must choose the Object type for action output and assign it to a variable of the same type.

Top comments (1)

Collapse
 
jeanfelipegf profile image
jeanfelipegf

Awesome!