> ## Documentation Index
> Fetch the complete documentation index at: https://docs.liberate.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Mapping node

# Mapping Node

The **Mapping Node** transforms data as it flows through your workflow. Use it to combine fields, format values, restructure objects, or prepare data for external systems.

> [!NOTE]
>
> The Mapping Node is the most commonly used node for data manipulation. It uses JSONata, a lightweight query and transformation language for JSON.

## Overview

Use a Mapping Node when you need to:

* Combine fields (e.g., first name + last name → full name)
* Reformat dates, numbers, or strings
* Restructure data for an API's expected format
* Extract values from nested objects
* Add calculated fields
* Filter or transform arrays

***

## Configuration Interface

When you open a Mapping Node, you'll see two panels:

| Panel | Purpose |
| - | - |
| **Left Panel** | Expression editor—write and test your transformation |
| **Right Panel** | Node settings—title, description, styling |

### Left Panel: Expression Editor

The expression editor has four sections:

**1. Sample Context (Top)**

Paste sample JSON data to test your transformation. This simulates what the node will receive at runtime.

**2. JSONata Expression (Middle)**

Write your transformation logic using JSONata syntax.

**3. Output (Bottom)**

See the real-time result of applying your expression to the sample context.

**4. Merge Toggle (Bottom Left)**

Control whether the output merges with or replaces existing context.

***

## Writing Transformations

### Basic Example

**Input context:**

```json theme={null}
{
  "firstName": "John",
  "lastName": "Smith",
  "policyNumber": "HO-12345678"
}
```

**JSONata expression:**

```jsonata theme={null}
{
  "fullName": firstName & " " & lastName,
  "policyId": policyNumber
}
```

**Output:**

```json theme={null}
{
  "firstName": "John",
  "lastName": "Smith",
  "policyNumber": "HO-12345678",
  "fullName": "John Smith",
  "policyId": "HO-12345678"
}
```

> [!TIP]
>
> With **Merge ON**, the original fields (`firstName`, `lastName`, `policyNumber`) are preserved and new fields are added.

***

## JSONata Syntax

JSONata is a powerful expression language. Here are the most common operations:

### Accessing Data

| Syntax | Description | Example |
| - | - | - |
| `fieldName` | Access top-level field | `firstName` → `"John"` |
| `object.field` | Access nested field | `claimant.firstName` → `"John"` |
| `array[0]` | Access array element | `items[0]` → first item |
| `$` | Reference root context | `$.policyNumber` |

### String Operations

| Operation | Syntax | Example |
| - | - | - |
| Concatenate | `&` | `firstName & " " & lastName` → `"John Smith"` |
| Uppercase | `$uppercase()` | `$uppercase(state)` → `"CA"` |
| Lowercase | `$lowercase()` | `$lowercase(email)` → `"john@email.com"` |
| Trim | `$trim()` | `$trim(name)` → removes whitespace |
| Substring | `$substring()` | `$substring(phone, 0, 3)` → `"555"` |
| Replace | `$replace()` | `$replace(phone, "-", "")` → `"5551234567"` |

### Date Operations

| Operation | Syntax | Example |
| - | - | - |
| Current timestamp | `$now()` | `"2025-02-17T14:30:00Z"` |
| Format date | `$fromMillis()` | `$fromMillis($toMillis(date), "[M01]/[D01]/[Y0001]")` |
| Parse date | `$toMillis()` | Converts date string to milliseconds |

### Conditional Logic

```jsonata theme={null}
{
  "priority": claimAmount > 50000 ? "high" : "standard",
  "assignee": lossType = "fire" ? "senior_adjuster" : "auto_adjuster"
}
```

### Working with Arrays

```jsonata theme={null}
{
  "firstItem": items[0],
  "itemCount": $count(items),
  "totalAmount": $sum(items.amount),
  "itemNames": items.name
}
```

> [!NOTE]
>
> For complete JSONata documentation, visit [jsonata.org](https://jsonata.org/).

***

## The Merge Toggle

The **Merge** toggle is critical—it controls how your transformation output is applied to the workflow context.

> [tab] Merge ON (Recommended)
>
> **Toggle: Blue/ON**
>
> * Preserves all existing context properties
> * Adds new properties from your transformation
> * Updates existing properties if keys match
>
> **Example:**
>
> Existing context:
>
> ```json theme={null}
> {
>   "tenantId": "acme-insurance",
>   "environment": "prod",
>   "firstName": "John",
>   "lastName": "Smith"
> }
> ```
>
> Your expression:
>
> ```jsonata theme={null}
> {
>   "fullName": firstName & " " & lastName
> }
> ```
>
> Result:
>
> ```json theme={null}
> {
>   "tenantId": "acme-insurance",
>   "environment": "prod",
>   "firstName": "John",
>   "lastName": "Smith",
>   "fullName": "John Smith"
> }
> ```
>
> ✅ System properties preserved, new field added.

> [tab] Merge OFF (Use with Caution)
>
> **Toggle: Gray/OFF**
>
> * Completely replaces the entire context
> * Only properties in your transformation output remain
> * System properties (`tenantId`, `environment`, etc.) are lost
>
> **Example:**
>
> Existing context:
>
> ```json theme={null}
> {
>   "tenantId": "acme-insurance",
>   "environment": "prod",
>   "firstName": "John",
>   "lastName": "Smith"
> }
> ```
>
> Your expression:
>
> ```jsonata theme={null}
> {
>   "fullName": firstName & " " & lastName
> }
> ```
>
> Result:
>
> ```json theme={null}
> {
>   "fullName": "John Smith"
> }
> ```
>
> ⚠️ Everything else is gone—including critical system properties!

> [!WARNING]
>
> Keep **Merge ON** unless you specifically need to replace the entire context. Turning it off will remove `tenantId`, `environment`, and other critical properties.

***

## Saving Your Work

> [!WARNING]
>
> **Two-Step Save Required!**
>
> When configuring a Mapping Node, you must click Save **twice**:
>
> 1. **First Save**: Click **Save** in the Expression Editor (left panel) to close the dialog
> 2. **Second Save**: Click **Save** in the Node Settings (right panel) to commit changes
>
> If you only save once and click away, **you will lose your changes**. This is a common mistake!

***

## Insurance Examples

### Format Claim Data for Snapsheet

**Input:**

```json theme={null}
{
  "claimType": "water",
  "claimDetails": "Basement flooded after pipe burst",
  "callerFirstName": "John",
  "callerLastName": "Smith",
  "policyNumber": "HO-12345678",
  "dateOfLoss": "2025-02-13",
  "timeOfLoss": "06:00"
}
```

**Expression:**

```jsonata theme={null}
{
  "claim": {
    "type": claimType,
    "description": claimDetails,
    "loss_date": dateOfLoss & "T" & timeOfLoss & ":00Z",
    "policy_id": policyNumber
  },
  "reporter": {
    "full_name": callerFirstName & " " & callerLastName,
    "relationship": "policyholder"
  }
}
```

**Output:**

```json theme={null}
{
  "claim": {
    "type": "water",
    "description": "Basement flooded after pipe burst",
    "loss_date": "2025-02-13T06:00:00Z",
    "policy_id": "HO-12345678"
  },
  "reporter": {
    "full_name": "John Smith",
    "relationship": "policyholder"
  }
}
```

***

### Normalize Phone Numbers

**Input:**

```json theme={null}
{
  "phone": "(555) 123-4567"
}
```

**Expression:**

```jsonata theme={null}
{
  "phoneFormatted": phone,
  "phoneDigitsOnly": $replace($replace($replace(phone, "(", ""), ")", ""), "-", "") ~> $replace(" ", "")
}
```

**Output:**

```json theme={null}
{
  "phone": "(555) 123-4567",
  "phoneFormatted": "(555) 123-4567",
  "phoneDigitsOnly": "5551234567"
}
```

***

### Calculate Claim Priority

**Input:**

```json theme={null}
{
  "claimType": "fire",
  "estimatedAmount": 75000,
  "isCommercial": false
}
```

**Expression:**

```jsonata theme={null}
{
  "priority": (
    claimType = "fire" ? "high" :
    estimatedAmount > 50000 ? "high" :
    isCommercial ? "medium" :
    "standard"
  ),
  "requiresSeniorAdjuster": claimType = "fire" or estimatedAmount > 100000
}
```

**Output:**

```json theme={null}
{
  "claimType": "fire",
  "estimatedAmount": 75000,
  "isCommercial": false,
  "priority": "high",
  "requiresSeniorAdjuster": true
}
```

***

### Extract Data from Nested Objects

**Input:**

```json theme={null}
{
  "policy": {
    "number": "HO-12345678",
    "holder": {
      "name": "John Smith",
      "address": {
        "street": "123 Main St",
        "city": "Austin",
        "state": "TX",
        "zip": "78701"
      }
    }
  }
}
```

**Expression:**

```jsonata theme={null}
{
  "policyNumber": policy.number,
  "holderName": policy.holder.name,
  "fullAddress": policy.holder.address.street & ", " & 
                 policy.holder.address.city & ", " & 
                 policy.holder.address.state & " " & 
                 policy.holder.address.zip
}
```

**Output:**

```json theme={null}
{
  "policyNumber": "HO-12345678",
  "holderName": "John Smith",
  "fullAddress": "123 Main St, Austin, TX 78701"
}
```

***

## Multiple Transformations

You can add multiple transformations to a single Mapping Node:

1. Click **+ Add mapping transformation**
2. Write your first expression and save
3. Click **+ Add mapping transformation** again
4. Write additional expressions

Each transformation runs in sequence, and each can access data added by previous transformations.

***

## Best Practices

### Test with Realistic Data

Always paste sample data that represents what your workflow will actually receive. This catches issues before deployment.

### Keep Transformations Focused

Do one logical transformation per Mapping Node. This makes debugging easier:

```
Mapping Node 1: Format claimant data
Mapping Node 2: Format claim details  
Mapping Node 3: Prepare API request body
```

### Use Descriptive Titles

Name your Mapping Nodes clearly:

| ❌ Bad | ✅ Good |
| - | - |
| Mapping | Format Claimant Name |
| Transform | Prepare Snapsheet Request |
| Data | Calculate Claim Priority |

### Handle Missing Data

Use the conditional operator to handle null values:

```jsonata theme={null}
{
  "fullName": firstName ? (firstName & " " & lastName) : "Unknown"
}
```

***

## Common Issues

### Expression Returns Nothing

**Symptom:** Output is empty or undefined.

**Fix:** Check that field names match exactly (case-sensitive). Use the Sample Context to verify your data structure.

### Lost System Properties

**Symptom:** `tenantId` or `environment` is missing after the Mapping Node.

**Fix:** Ensure **Merge** is toggled ON (blue).

### Changes Not Saved

**Symptom:** Expression reverts to previous version.

**Fix:** Remember the two-step save—Save in the expression editor, then Save in the node settings panel.

### Date Formatting Issues

**Symptom:** Date appears in wrong format.

**Fix:** Use `$fromMillis()` with proper format string:

```jsonata theme={null}
$fromMillis($toMillis(dateString), "[M01]/[D01]/[Y0001]")
```

***

## Next Steps

> [card] [Task Node](https://docs.liberate.ai/workflows/nodes/task-node.md)
>
> Send transformed data to external systems

> [card] [AI Prompt Node](https://docs.liberate.ai/workflows/nodes/ai-prompt-node.md)
>
> Parse unstructured text before mapping

> [card] [Code Node](https://docs.liberate.ai/workflows/nodes/code-node.md)
>
> Use JavaScript/Python for complex logic

> [card] [Context Deep Dive](https://docs.liberate.ai/workflows/concepts/context.md)
>
> Understand how data flows through workflows


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.