RecordsTransform Core Add-On Module.


This module allows you to apply custom transformation and mapping to the source records before they are uploaded to the Target.
It gives you the additional great benefits over the existing Values Mapping feature.

Table of Contents



A significant advantage of this Add-On, compared to Values Mapping, is that it enables field updates using multiple different sObjects as data sources.

Furthermore, it allows for complex transformations using customized expressions.


The terminology used in this article includes:

  • "source" - refers to the SObject, field, or record from which values are derived for the transformation.

  • "target" - denotes the SObject, field, or record that is updated as a result of the transformation process.

  • Specifically for the "lookupSource" property, "source" implies "the record from the Data Source" and "target" indicates "the record from the Data Target".

Sample of record transformation.

Let's see the example of the configuration below:

"objects": [
    {
        "operation": "Upsert",
        "externalId": "Name",
        "query": "SELECT Name FROM Account"
    }
],
"dataRetrievedAddons" : [
    {
        "module" : "core:RecordsTransform",
        "args": {
            "fields": [
                {
                    "alias": "accountCategory",
                    "sourceObject": "Account",
                    "sourceField": "Category__r.Name"
                },
                {
                    "alias": "accountRegion",
                    "sourceObject": "Country__c",
                    "sourceField": "Region__r.Name",
                    "includeFields": [
                        "BusinessAccount__c"
                    ]
                }
            ],
            "transformations": [
                {
                    "targetObject": "Account",
                    "targetField": "CategoryName__c",
                    "formula": "formula.accountCategory"
                },
                {
                    "targetObject": "Account",
                    "targetField": "CategoryAndRegionName__c",
                    "expressions": [
                        "formula.exists = formula.accountCategory && formula.accountRegion"
                    ],
                    "formula": "formula.exists ? formula.accountCategory + ' (' + formula.accountRegion + ')' : null"
                }
            ]
        }
    }
]

The same result can be achieved by using the Lookup Expression option, which explicitly defines the comparison of Country__c.BusinessAccount__c with Account.Id to evaluate the accountRegion during transformation:

{
    // .... 
                    "alias": "accountRegion",
                    "sourceObject": "Country__c",
                    "sourceField": "Region__r.Name",
                    "lookupSource": "source",
                    "lookupExpression": "source.BusinessAccount__c == target.Id",
                    "includeFields": [
                        "BusinessAccount__c"
                     ]
       // ....
}
               

Our object model is below:

sObject Field (Field type)
Account Name (Account name field)
Account Category__c (lookup to Category__c)
Account CategoryName__c (Picklist)
Account CategoryAndRegionName__c (String)
Country__c Name (Country name field)
Country__c BusinessAccount__c (lookup to Account)
Country__c Region__c (lookup to Region__c)
Region__c Name (Region name field)

Requirements.

Our task involves extracting values from various source fields, conducting a series of calculations, and subsequently updating two target account fields with the outcomes.

The transformations needed are as follows:

  • Account.CategoryName__c should be set to the value of Account.Category__r.Name.

  • Account.CategoryAndRegionName__c should combine the values of Account.Category__r.Name and Country__c.Region__r.Name, formatted as Account.Category__r.Name + ' (' + Country__c.Region__r.Name + ')'.

Solution Utilizing the Core RecordsTransform Add-On Module

Step 1: Define the Source Fields

We specify two source fields (categorized under the Field object type) with the designated aliases:

  • accountCategory: This sources its value from Account.Category__r.Name.
  • accountRegion: This retrieves its value from Country__c.Region__r.Name.

But, how does the Add-On pinpoint the Country record?

With the BusinessAccount__c lookup field at its disposal, it efficiently locates the first child Country that references the targeted Account, leveraging its data for the transformation. This selection method is consistently applied, even within many-to-one relationships, where the first child object is prioritized.


Step 2 Setup lookup relationships.

As mentioned above, to select the child Country record by its parent Account, we use the Country__c.BusinessAccount__c as a parent-child lookup field. Therefore, BusinessAccount__c should be included in the query string of Country__c.

The usual method for including the BusinessAccount__c field in the query string of Country__c is by utilizing the includeFields property in the accountRegion definition. This allows the Add-On to link between Account and Country:

{
  "includeFields": [
    "BusinessAccount__c"
  ]
}

This configuration adds Country__c into the setup and incorporates the BusinessAccount__c lookup into the query string of Country__c.

The benefit of using the includeFields property to add extra fields is that it eliminates the need to include all readonly objects in your export.json. These objects are only used by the Add-On and not required elsewhere.

However, if you prefer to directly add Country__c to the export.json, the includeFields section can be omitted. Ensure that BusinessAccount__c is included in the query string of Country__c:

{
    "operation": "Readonly",
    "externalId": "Name",
    "query": "SELECT Name, BusinessAccount__c FROM Country__c"
}
Notes:
  • The Add-On automatically determines which SObject (Account or Country) is the parent and which is the child, so you don't need to manage their relationship details.

Step 3 Define the target fields and transformation expressions.

In the transformations array, we specify two fields of the Account to be updated following the transformation: CategoryName__c and CategoryAndRegionName__c.

Each Transformation object contains these properties:

  • formula: A required expression whose value is used to update the target field. Source aliases can be used within this expression, such as formula.[ALIAS], e.g., formula.accountCategory. The term formula denotes a temporary JavaScript object defined in the scope of the current target record.

  • expressions: An optional list of expressions executed for each target record before the formula. This feature allows for additional operations and the augmentation of the formula object with extra properties, which may be required for the primary formula expression.

The full specification of the args properties.

Property name Is mandatory Property type Description
fields Yes Array of Field objects List of the data sources to transform.
Field.alias Yes string Variable name (akin to JavaScript variable naming), allows for the inclusion of this Field in the transformation expression.
Field.sourceObject Yes string SObject used as the data source for the transformation.
Field.sourceField Yes string Field belonging to the sourceObject which is used as the value source for the transformation.
Field.includeFields No Array of strings List of fields to be incorporated into the original query string of the sourceObject to select the parent object within a relationship.

➦ Any field, including lookups and referencing fields like Account.Name, can be added.
Field.lookupExpression No string,
Any Js expression
To create a customized lookup search, you can utilize the lookupExpression instead of the automated lookup search, by specifying includeFields on the child object within a relationship.

➦ The lookupExpression is a JavaScript expression designed to select a parent record from the entire set of records, mimicking the functionality of a regular lookup.
➦ It employs two constants, source and target:
- source refers to the current source record, which is derived from either the Data Source or Data Target, depending on the lookupSource setting.
- target consistently represents the record intended for transformation.
By comparing records based on properties, it's possible to determine the appropriate record for setting the current field alias, facilitating its use in further transformation expressions.
Field.lookupSource No string,
Acceptable values:
'source' or 'target'
Defines whether the lookupExpression should be run in a loop over the records from the Data Source or Data Target.

source: It iterates over all data source records. In this case, the given field finally selects and evaluates the record from the Data Source.
target: It iterates over all data target records. In this case, the given field finally selects and evaluates the record from the Data Target.
Field. isConstant No boolean, fefault false Setting this property to true ensures that the lookupExpression for this Field is calculated only once per job, functioning similarly to a cached value. The first successful result is then utilized in all subsequent transformations.
transformations Yes Array of Transformation objects List of the fields to update.
Transformation.targetObject Yes string sObject to update.
Transformation.targetField Yes string targetObject's field to update.
Transformation.formula Yes string Final Js expression, which is running for each target record to update the targetField.
Transformation.expressions No Array of strings A collection of JavaScript expressions, all evaluated before the main Transformation.formula expression is executed.

➦ This feature enables you to augment the formula object with additional properties, assisting in the construction of the final formula expression.

Additional Information About This Add-On Module

  • The sourceField property must be set to a field that is queryable using SOQL on the source object. For instance, if you define Category__r.Name for the Account, the Add-On internally generates a query similar to: *SELECT Id, Category__r.Name, ...... FROM Account ....., etc.

  • Lookup fields specified in the includeFields are always included in the SOQL query for the sObject, just as if you were constructing the query manually. As a result, these lookup fields may also be migrated to the Target org as part of the query process, similar to other fields. To prevent this and ensure these fields are only used for transformation purposes, consider utilizing the excludedFromUpdateFields property, which prevents fields from being uploaded to the Target.

  • There are two options for incorporating this Add-On into your export.json:

    • As part of the object definition (OnBeforeUpdate event declaration). In this scenario, the Add-On transforms the final version of the records just before they are uploaded to the target org.

    • Globally (OnDataRetrieved event declaration). In this case, it operates on not the final version of the records, meaning the lookup fields are not yet populated.

  • This Add-On executes AFTER the Values Mapping process has been completed.

See also Supported Add-On Api Events

Last updated on 13th Apr 2024