One of the key aspects of sync configuration is field mapping. Field mapping defines which columns from your model query results should appear in your destination and how. In other words, it's a way of relating model columns to destination fields or properties.
"Columns" vs. "fields" vs. "properties": Though some may use these terms
interchangably,
Hightouch uses the term "columns" to refer to a set of vertical data values in
a source or model and "fields" or "properties" to refer to them in a destination.
Depending on your destination, you can map your data with either the basic mapper or the advanced mapper. The basic mapper maps columns to fields in a one-to-one way. The advanced mapper gives the additional options of:
You can start with either the source or destination input fields when using either basic or advanced mapper.
The Hightouch UI offers this flexibility to enable you to map data the way that makes the most sense for you.
For example, you may approach mapping with an idea of all model columns you want to send to your destination.
To do so, click Add mapping and select each model column in the left-hand inputs.
Then select the appropriate destination fields to map them to in the corresponding right-hand dropdowns.
Conversely, you may know all the destination fields you need to sync to.
Select each destination field from the dropdowns on the right and map the appropriate model columns on the left.
You can also select to Suggest mappings.
This option proposes relevant destination fields for model columns.
For example, a model column named email_address would receive a suggested destination field like Email.
This autocompletion works by searching for matching and near-matching column and field names.
Before saving your configuration, you should confirm that the autocompleted suggestions have made the correct selections.
With the basic mapper, you tell Hightouch which columns in your source to feed into which fields in your destination. For example, you can use the basic mapper to relate model columns to destination fields like these:
You can open the advanced mapper by clicking the source field you want to map. If you click a source field and the advanced mapper doesn't appear, it isn't supported. Please if you have a use case requiring the advanced mapper on a destination that doesn't support it.
Mapping column values is similar to the basic mapper's functionality. You can search for and select the model column name you want to map to a destination field.
By default, Hightouch syncs any null values found in your model query results to your destination. You can select to sync nothing instead of null values by enabling Don't sync null values.
With static mapping, you can specify a constant value to use for each field value. For example, suppose you want to map the string value EMEA for every record's region field value in a destination. You can do this with static mapping:
Open the advanced mapper by clicking on a model column.
Select Static value and the value's data type: String, Number, Boolean, or Null.
Enter the desired value in the field provided.
Click Apply.
In the field input to the right of the static value, select the destination field name to which you want to map the static value.
The template mapper is convenient when your destination requires data in a specific format, and you want to avoid baking this specificity into your model.
For example:
Webflow requires slugs not to have any special characters. You can use the template mapper's regex_replace function to remove them.
You want to validate email addresses before sending them to Mailchimp or another email service provider.
You want to enable lead routing in your destination using Liquid conditionals without touching your central dbt model.
To create nested objects or arrays, you need to use the inline
mapper.
Open the advanced mapper by clicking on a model column.
Select Template, then select a Variable and Function. The function's code automatically appears in the editor window.
Click Apply.
In the field input to the right of the templated value, select the destination field name to which you want to map the templated value.
In the example screenshot, the template uses the function {{ row['last_name'] | includes: "Stark" }} to check checks if a row's last_name column includes the string "Stark". If it does, the row is processed. If it doesn't, the row is rejected.
Beyond using row values, accessible by {{ row['column_name'] }}, you can also access any of the variable values present in the advanced mapper.
These variable values are available on the context object.
For example, you could you use {{ row['id'] | concat: context['sync_run_id'] }} to concatenate a row's ID with the current sync run's ID.
The template mapper supports all Liquid native features and also includes Liquid-inspired functions.
To learn more about the Liquid templating language, skip to the Liquid reference section in this doc or check out the Liquid reference documentation.
The inline mapper is only available for certain destinations and is currently in beta. Please if you'd like to be considered for early access.
When syncing data to a marketing automation or enterprise resource planning (ERP) tool, you may need to nest related entities. For example, you may have nested items in an invoice or nested entities for a user: associated devices, shipping address, pets, etc. The inline mappers allows you to create these nested objects and arrays from your model query results without altering your model definition.
Each destination has its own formatting expectations for these nested entities. For example, in Stripe, an invoice object supports an items field that expects an array of items.
The inline mapper lets you model your data once and format it during sync configuration rather creating a separate model for each destination requiring nested objects or arrays.
The object inline mapper allows you to construct objects and map them to destination fields usings columns from your model. This section walks through constructing an object for the shipping field in Stripe's customer object.
In the destination field input on the right, select the field name to which you want to map an object, for example, Shipping Address.
The model column input on the left autopopulates to Object mode if the selected field is of type object. If the type of the field is not provided, open the advanced mapper by clicking on the source input field and select Create an object.
Select the relevant destination fields you want to map values to and map the nested fields as needed.
Given the previous example row and the mappings shown in the screenshot above, Hightouch would sync the following payload:
The array inline mapper allows you to construct an array of objects and map them to destination fields using a model column that contains an array of objects. This section walks through constructing a line items array for Stripe's quote object. You would use the same steps for any other object arrays you want to create.
To use the inline mapper to create an array of objects, the query results from your model need to have a certain format. Specifically, they should appear as an array of objects, like the example items field in the entity relationship diagram (ERD) above.
If you don't already have a data field formatted like this, you can define your model using a SQL query that constructs an array of objects from other fields.
For example, imagine you have a line_items data table where each row represents an invoice item. The columns are:
invoice_id for the ID of the invoice the item belongs to
customer_id for the ID of the customer who purchased the item
amount for the cost of item
description for a short description of the item
For example:
invoice_id
customer_id
amount
description
in_1
cust_abcd
55
Waffle Maker
in_1
cust_abcd
7
Dog Chew Toy
in_2
cust_efgh
12
HDMI Cable
in_3
cust_abcd
45
Humidifier Filters
in_3
cust_abcd
109
Electric Kettle
in_3
cust_abcd
15
Wall Calendar
in_4
cust_ijkl
25
Mediterranean Cookbook
in_4
cust_ijkl
10
AAA Batteries
You want to sync an array of items for each invoice for each customer. For example, for customer_abcd from the preceding table, they would have two separate invoice objects, each with their own items array, one for the invoice with ID in_1 and one for the in_3 invoice:
To make these fields available in the inline mapper to construct an items array, you would need to include SQL like this in your model definition:
select
inv.customer_id,
inv.invoice_id,
array_agg(object_construct(it.*)) as items
from
line_items inv
join items it on it.invoice_id = invoice._id
groupby1,
2
This query selects the customer_id and invoice_id as well as all properties—in this case just description and amount—on each item and then aggregates them into an array of objects. The group by statement groups them based on the customer_id and invoice_id so that each aggregated array is for one invoice for one customer. Without the inline mapper, you would need to write more complex SQL manually constructing each item attribute as part of the item object.
Once your model query results have an array of objects to pull data from, you can use the inline mapper to configure as many syncs as you need to sync these items.
In the Field Mapping section of your sync configuration, in the destination field input on the right, select the field name to which you want to map an array, for example, Line items.
The model column input on the left autopopulates to Array mode if the selected field is of type array. If the type of the field is not provided, open the advanced mapper by clicking on the source input field and select Create an array.
You will be prompted to pick a column that contains an array of objects. Select your desired column from the list of compatible columns. If no columns appear, ensure your model query results conform to the required data format.
Select the relevant destination fields you want to map values to and map the nested fields as needed.
The columns available under the array inline mapper are properties of the previously selected column.
Hightouch uses the first 100 rows from your query to extract the available properties at each index of the array. To add additional properties that may be missing, type into the input field and select the custom option or press Enter.
Hightouch only processes properties if the mapped object property at the index of the array exists.
For example, if <Your Column>[0].price exists and <Your Column>[1].price doesn't exist, items[0].price will be mapped and items[1].price won't be mapped. Hightouch syncs null values if you don't choose to ignore them.
For each row in your query, the array created using the inline mapper matches the length of the array in your column.
Given the previous example row and the mappings shown in the screenshot above, Hightouch would sync the following payload:
You may need to sync arrays or objects with more deeply nested objects. For example, you may need to sync a Shipping Address object with this format:
{"name":"Jane Doe","address":{"address_line_1":"123 High Street","address_line_2":"","city":"San Francisco","state":"California","postal_code":"94105","country":"USA"},"phone_number":"4151234567"}
The "address" key expects a further nested object. Hightouch supports nesting up to two levels deep. You can do this by selecting Create an object or Create an array while already using the inline mapper.
The double handlebars enclose a Liquid snippet that generates an output. The column name, company in the preceding example, should be in single quotes inside the square brackets.
Hightouch also provides these alternative syntaxes:
{{ row.company }}
{{ company }}
These shorter alternatives can be useful when templating messages, such as when syncing to Slack, Mattermost, Microsoft Teams, or to the SMTP Email destination.
Make sure to use the {{ row['first name'] }} syntax if your model column name contains spaces.
Functions follow this format:
{{ row['last_name'] | includes : 'Stark' }}
A single pipe (|) comes after the variable and before the name of the function and any necessary parameters. See the Liquid Reference or Liquid Cheatsheet for a complete list of available functions.
You can use more than one Liquid function in a template by chaining them. For example, you may want to put a string variable into camel case before hashing it. To chain functions, separate them with a single pipe (|):
Conditionals are also helpful to guard against missing values.
For example, you could use the following Liquid snippet to send a null value for empty values.
This is helpful if you need to map a column that exists for some rows but not others:
You can also use Liquid to set a default value, in case an input value is null, false, or empty. For example, this Liquid snippet sets the revenue field as 0 if the value is missing or null in a model's row:
{{ row['revenue'] | default: 0 }}
Be sure to change revenue to the column name you want to set default values for.
See Liquid Math Functions for a complete list of math functions.
In Hightouch, the absolute value and rounding functions are some of the most commonly used:
Use the abs function to send an absolute value:
{{ row['value'] | abs }}
Use the round function to round a value to the nearest integer or a specified number of decimals:
Hightouch doesn't support money functions.
If you would like to format currency amounts, such as prices, you can set this up manually by using the following template:
reverse: reverses the order of items in the groups
join: transforms the single groups of items back into strings
The second part is a conditional that displays the currency amount in the correct format.
If your model column contains currency amounts without decimal places, make sure to remove the decimals variable from the Liquid expression and update the slice functions accordingly.
See Liquid String Functions for a complete list of string functions.
In Hightouch, the capitalize, strip, and append functions are some of the most commonly used:
Use the capitalize function to capitalize the first letter of a string:
{{ row['title'] | capitalize }}
Use the strip function to remove all whitespace from the left and right sides of a string:
{{ row['title'] | strip }}
Use the append function to add a file extension to a string:
You can use the Liquid split function to isolate a certain part of a string.
For example, suppose you have a model column that returns URLs, including query parameters.
An example value may look like this: www.example.com/?gclid-123.
You may want to send the base URL (www.example.com/) as one field and one of the query parameters as another field.
Query parameters often include click IDs, such as the gclid or fbclid that you should include on events you send to Google Ads or Facebook Conversions (or Facebook Offline Conversions) respectively.
For the example value www.example.com/?gclid-123, this Liquid snippet would return the base URL, www.example.com/:
{{ row['column_name'] | split: "?gclid-" | first }}
And this Liquid snippet would return the gclid value, 123:
{{ row['column_name'] | split: "?gclid-" | last }}
You can use Liquid to change a timestamp's time and date values. For example, you may want to send a date one day earlier than the original. This snippet subtracts 24 hours (represented as 86,400 seconds) from the original date in the column:
If your model columns contain object type values, you may want to sync only one or some of the object's properties to your destination.
You can do this in the template mapper using the dot notation.
Specifically, you can write a Liquid expression containing the model column's name and the property's name: {{ row['model_column'].property }}
You can use dot notation for field mapping and record matching, but only for destinations that support Liquid templating.
Furthermore, dot notation doesn't work when testing a row.
To test your sync, trigger a sync run and take a look at the live debugger.
For example, suppose you had a model column named invoice that contains objects with this structure:
{"invoice_number":"INV-001","issue_date":"2023-06-08","due_date":"2023-06-30","customer":{"name":"John Doe","email":"johndoe@example.com","address":"123 Main St, City, State, ZIP"},"items":[{"description":"Product A","quantity":2,"unit_price":10.99,"total_price":21.98},{"description":"Product B","quantity":1,"unit_price":15.99,"total_price":15.99}],"subtotal":37.97,"tax":3.60,"total":41.57,"currency":"GBP"}
You may only want to map the total column to a price field in your destination.
You could do this by including the following Liquid in the template mapper:
{{ row['invoice'].total }}
You can also use this to map nested properties, for example, customer.name:
{{ row['invoice'].customer.name }}
If you want to sync multiple object properties individually, you can use these types of expressions for multiple mappings in your sync configuration.
Make sure you've set the model column's type as Object / Array in the model's Columns tab.
Otherwise, Hightouch syncs an undefined value to your destination.
Dot notation only works with model columns that contain single objects. For arrays of objects, you can use the inline mapper.
If you edit the field mappings in your sync configuration, the sync engine automatically reprocesses the entire model query result set during the next sync run. Depending on the selected sync mode, Hightouch syncs the model rows detected as added or as changed by change data capture to your destination.
If the sync uses either update or upsert mode, Hightouch resyncs previously synced rows (with the updated mappings) as "changed" rows. If the sync uses insert mode, Hightouch doesn't reprocess previously synced rows. Instead, it only syncs model rows that are detected as added after the field mapping change was saved in your sync configuration.
Most changes to your model columns aren't automatically detected by sync configurations.
Hightouch handles the changes differently depending on whether columns are added, renamed, or removed from your model definition, or if you change a column's data type.
If you add a new column to your model, Hightouch doesn't automatically add it as a field mapping to your sync configurations. This is because Hightouch doesn't know which columns you would like to sync to the destination, and which destination fields they should be mapped to. Follow the field mapping instructions to include new columns in your sync configuration.
You need to preview and save your model to have new columns appear in the Hightouch UI.
If you rename a column in your model, all syncs that had that column mapped in their configuration fail with an Unknown field name error.
The error message also contains the original name of the renamed column. To resolve this, remove or update the relevant field mappings in your sync configuration.
Changes to model column names aren't detected for All / Mirror type syncs.
If you remove a column from your model, Hightouch doesn't automatically remove it from the field mappings in the sync configuration. Make sure to remove the mapping manually.
If you change a model column's data type, the sync engine considers this update as a field mapping update and reprocesses all model rows during the next sync run.
As explained in the primary key updates section, if you update a model's primary key by selecting a different column, you need to trigger a full resync or reset change data capture (CDC) for all syncs that use that model. Otherwise, change data capture can't process your model data correctly, which can make your syncs fail.
If you rename a field in your destination, you need to update the mapping to this field in your sync configuration. Select the new field name from the dropdown menu and save your changes.
Ready to get started?
Jump right in or a book a demo. Your first destination is always free.