I have the following invocable class. It currently functions as I would like (updating the Interaction__c record with a ContactId that is found using a conditional SOSL query and subsequent regular expression on first name fields and last name). However, the issue I am running into is too many SOSL queries: 21.

I assumed that everything was already bulkified, since it is a list of interaction__c records being passed into the class. However, that does not appear to be the case. How can I bulkify this class to pass in the list of interaction__c records, return a list of interaction__c records to update so that I can update them in the flow that calls it. The reason I would like to do that is it keeps the class more flexible and easier to implement in other flows. Below is my script:

public class InteractionContactMatcher {

    public class InteractionInput {
        @InvocableVariable(required=true) public String FirstName;
        @InvocableVariable(required=true) public String LastName;
        @InvocableVariable public String Email;
        @InvocableVariable public String MobilePhone;
        @InvocableVariable public String HomePhone;

    @InvocableMethod(label='Match Interaction to Contacts' description='Finds the first matching contact based on Interaction data.')
    public static List<Id> matchContacts(List<InteractionInput> inputs) {
        List<Id> matchedContactIds = new List<Id>();

        for (InteractionInput input : inputs) {
            List<Contact> potentialMatches = new List<Contact>();

            if (input.Email != null && input.Email != '') {
            } else {
                potentialMatches.addAll(findMatchingContactsByPhone(input.MobilePhone, input.HomePhone));

            // Filter contacts based on sanitized names and get the first match
            Id matchedContactId = filterContactsByNamesAndReturnFirstMatch(potentialMatches, input.FirstName, input.LastName);
        return matchedContactIds;

    private static List<Contact> findMatchingContactsByEmail(String email) {
        List<List<SObject>> searchResults = [FIND :email IN EMAIL FIELDS RETURNING Contact(Id, FirstName, LastName, Banner_First_Name__c, Preferred_First_Name__c,Interaction_First_Name__c, Import_First_Name__c)];
        return (List<Contact>)searchResults[0];

    private static List<Contact> findMatchingContactsByPhone(String mobilePhone, String homePhone) {
        List<String> phones = new List<String>();
        if (mobilePhone != null && mobilePhone != '') phones.add(mobilePhone);
        if (homePhone != null && homePhone != '') phones.add(homePhone);
        String phoneSearchString = String.join(phones, ' OR ');

        List<List<SObject>> searchResults = [FIND :phoneSearchString IN PHONE FIELDS RETURNING Contact(Id, FirstName, LastName, Banner_First_Name__c, Preferred_First_Name__c, Interaction_First_Name__c, Import_First_Name__c)];
        return (List<Contact>)searchResults[0];

    private static Id filterContactsByNamesAndReturnFirstMatch(List<Contact> contacts, String firstName, String lastName) {
        String sanitizedInputName = sanitize(firstName) + sanitize(lastName);

        for (Contact c : contacts) {
        if (c.Banner_First_Name__c != null && sanitizedInputName.equals(sanitize(c.Banner_First_Name__c + c.LastName))) {
            System.debug(sanitize('c.Banner_First_Name__c MATCH ' + c.Banner_First_Name__c + c.LastName));
            return c.Id;
        } else if (c.Preferred_First_Name__c != null && sanitizedInputName.equals(sanitize(c.Preferred_First_Name__c + c.LastName))) {
            System.debug(sanitize('Preferred_First_Name__c MATCH ' + c.Preferred_First_Name__c + c.LastName));
            return c.Id;
        } else if (c.FirstName != null && sanitizedInputName.equals(sanitize(c.FirstName + c.LastName))) {
            System.debug(sanitize('FirstName MATCH ' + c.FirstName + ' ' + c.LastName));
            return c.Id;
        } else if (c.Import_First_Name__c != null && sanitizedInputName.equals(sanitize(c.Import_First_Name__c + c.LastName))) {
            System.debug(sanitize('Import_First_Name__c MATCH' + c.Import_First_Name__c + ' ' + c.LastName));
            return c.Id;
        } else if (c.Interaction_First_Name__c != null && sanitizedInputName.equals(sanitize(c.Interaction_First_Name__c + c.LastName))) {
            System.debug(sanitize('Interaction_First_Name__c MATCH' + c.Interaction_First_Name__c + ' ' + c.LastName));
            return c.Id;            
        System.debug('No Matches');
        return null; // No match found

    private static String sanitize(String value) {
        if (value == null) return '';
        return value.replaceAll('[^A-Za-z]', '').toLowerCase();

1 Answer 1


You are currently doing one SOSL query for each InteractionInput. That is why you are hitting the SOSL limit.

You can bulkify the query by using OR in the query, as explained here: https://salesforce.stackexchange.com/a/173806/17819

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .