Accelerate the Value of Data

Custom Merge Service

Learn how the SFDC connector enables you to use Custom Merge Service to implement the merge functionality.

The Custom Merge Service calls the Standard Merge Service for merging multiple objects. It is not mandatory to call the Standard Merge service for merging objects. Merging objects can be completed using the custom code. You can call a Standard Merge Service using the Custom Merge Service code.

Request

POST /customMergeService

Body

{
  "type": {Salesforce object type} // e.g. Account
  "ids": [] // list of ID's to merge
}

Response

HTTP CODE 200

The following table describes parameters required for the merge operation.

Table 1. Parameters for Merge Operations

Parameter

Type

Required

Description

success Boolean true Defines the status of the merge operation.

The Possible values are true or false.

winnerId String true Defines the sobject ID for the winners.
loserIds Array of Strings true Defines the list of loser IDs.
message String false Defines the error messages.

{
  "success": true/false;
  "winnerId": {winnerId} // winner sobject id
  "loserIds": [] // list of loser ids,
  "message": "Error message"
}

Profile Configuration

You need to add customMergeService parameter to profile configuration to switch to Custom Merge Service.

Example

{
    "reltio": {
        ...
    },
    "salesforce": {
        ...
        "customMergeService": "/customMergeService" // path to custom merge service.
    }
}

Mapping configuration

To use custom merge, add customMerge parameter for entity type in the mapping.
Note: By default, the Standard Merge Service is used if the customMerge parameter is missing and has a false value.

Example for Mapping


[
  {
    "isActive": true,
    "processMerge": true,
    "customMerge": true,
    "sfdcSource": "configuration/sources/SFDC",
    "sobject": {
      "type": "Account"
    },
    "reltioObjectType": "configuration/entityTypes/HCP",
    "to_salesforce": {
      ...
    },
    "to_reltio": {
      ...
    }
  }
]

Example for Custom Merge Service

@RestResource(urlMapping='/customMergeService')
global with sharing class ReltioCustomMergeService {
    global class HealthcheckResult {
        String status = 'OK';
    }
    
    global class ReltioCustomMergeServiceResult {
		boolean success { get; set; }
        String winnerId;
        List<String> loserIds;
		String message { get; set; }
	}

	public class MergeException extends Exception {
	}
    
    @HttpGet
    global static HealthcheckResult doGet() {
        return new HealthcheckResult();
    }
    
    @HttpPost
    global static ReltioCustomMergeServiceResult doPost(String type, List<String> ids){
        ReltioCustomMergeServiceResult result = new ReltioCustomMergeServiceResult();
        
        if (type == 'Account' || type == 'Contact') {
            try {
                // ids array is sorted alphabetically. The last item has the highest value
                // Winner id has lowest value
                String winnerId = ids[0];
                List<String> loserIds = new List<String>();
                for (Integer i = 1; i < ids.size(); i++) {
                    loserIds.add(ids[i]);
                }
                                
                System.debug('Winner ID: ' + winnerId);
                System.debug('Loser IDs: ' + loserIds);
                
                // Merge in this example will be done by calling standard merge service
                // Standard merge service allows to merge up to 3 objects at one time (one winner and up to 2 losers)
                // If total objects count greater than three, then need to split losers to chunks.
                List<String> chunk = new List<String>();
                for (Integer i = 0; i < loserIds.size(); i++) {
                    chunk.add(loserIds[i]); // Split loser ids to chunks. Each chunk has up to 2 objects
                    if (chunk.size() == 2 || i == loserIds.size()-1) {
                        System.debug('Merge winner and chunk of losers: ' + chunk);
                        doMerge(type, winnerId, chunk); // call standard merge service for each chunk
                        chunk.clear();
                    }
                }
                
                result.success = true;
                result.winnerId = winnerId;
        		result.loserIds = loserIds;
			} catch (Exception e) {
                System.debug('Unexpected exception: ' + e);
                result.message = e.getMessage();
				result.success = false;
            }
        } else {
            System.debug('Type' + type + 'is not supported');
            result.success = false;
            result.message = 'Type' + type + 'is not supported';
            return result;
        }
        
        return result;
    }
    
    public static void doMerge(String type, String winnerId, List<String> loserIds) {
        if (type == 'Account' || type == 'Contact') {
            System.debug('Execute standard merge for type: ' + type + ' Winner ID: ' + winnerId + ' Loser IDs: ' + loserIds);
            mergeStandardObject(type, winnerId, loserIds);
        } else {
            System.debug('Type' + type + 'is not supported');
			throw new MergeException('Custom merge for type' + type + ' is not supported');
        }
    }
                                     
    private static void mergeStandardObject(String type, String winnerId, List<String> loserIds) {
		sObject winner = getWinner(type, winnerId);
		String query = 'Select Id from ' + type + ' where id in :loserIds';
		System.debug('Get losers query: ' + query);
		List<sObject> objectsToMerge = (List<sObject>)Database.query(query);

		for (sObject objectToMerge: objectsToMerge) {
			if (type == 'Account') {
				merge ((Account) winner) (Account) objectToMerge;
			} else if (type == 'Contact') {
                merge ((Contact) winner) (Contact) objectToMerge;
			}
			System.debug('Successfuly merged ' + type + '(' + winnerId + ', ' + objectToMerge.Id + ')');
		}
	}
                                     
    private static sObject getWinner(String type, String winnerId) {
        String query = 'select Id from ' + type + ' where Id = :winnerId';
        System.debug('Get winner query: ' + query);
		List<sObject> winners = Database.query(query);
		if (winners.size() == 0) {
			throw new MergeException(type + ' for id ' + winnerId + ' is not found');
		}
		return winners[0];
	}
}
 

Merging of Multiple Objects

The Custom Merge Service enables to override the Standard Merge Service logic. It is not mandatory to call the Standard Merge Service to perform the objects merge, it can be completely done using the custom code.

The Custom Merge Service allows calling Standard Merge Service from the code to perform the object merge.

Note: The custom merge service can merge any number of objects. As explained in the example of a custom merge service above, there’s a call to the Salesforce out-of-the-box merge service (doMerge(type, winnerId, chunk). This merge function takes a maximum of three object IDs as parameters. If you need to merge more than three objects, then the standard merge service must be called several times with up to three objects in each call. You can call this function multiple times. For more information, see the above example in Example for Custom Merge Service.

Retry Logic for Merge Request

The connector can retry the merge requests based on the service response for the Custom Merge Service.

The requests would be retried repeatedly when the response contains "success": false.

You can configure the retry count using salesforce.numRetries parameter in the relevant profile. For more information, see Configure your Salesforce Connector Profile.

Note: The connector will retry the merge request if the custom merges service from SFDC returns "success": false to avoid data inconsistency.

You can’t retry the requests if the Custom Merge Service provides an incorrect response structure (the structure without the winner or loser ID).