# Understanding JOLT operators (wildcards)

JOLT operators, also known as **wildcards**, are one of the most powerful features of the framework. They allow you to manipulate values, capture field names, handle optional inputs, and build flexible structures even when the input format varies.

In this guide, you’ll see how each operator works, what kinds of problems it solves, and how to use it to simplify both basic and advanced transformation scenarios.

{% hint style="success" %}
**Tip:** Test the examples from this document in the [JOLT playground](https://jolt-demo.appspot.com/#inception).
{% endhint %}

## **Important concepts**

Until now, we’ve covered the essential concepts of JOLT. Before moving forward with the advanced operations, we need to introduce two key elements used throughout all JOLT specifications: **LHS** and **RHS**.

### **LHS and RHS**

Every JOLT operation is built around two sides:

* **LHS (Left Hand Side):** The part before the colon (`:`), where we **select** or **match** fields from the input.
* **RHS (Right Hand Side):** The part after the colon (`:`), where we **assign** or **map** values to the output.

Operators behave differently on the **LHS** and the **RHS**, and understanding this distinction is essential for building powerful, adaptable transformation rules.

Example:

```json
[
 {
   "operation": "shift",
   "spec": {
LHS -> "customer": {
 LHS ->  "name": "client.fullName",  <- RHS
 LHS ->  "birhtDate": "client.dateOfBirth",  <- RHS
 LHS ->  "address": "client.address.street",  <- RHS
 LHS ->  "country": "client.address.country"  <- RHS
     }
   }
 }
}
]
```

## **Deep dive into operators**

Let’s take a closer look at each operator and see how it behaves in real transformations. In the next sections, you’ll find explanations and examples that show exactly how each one works and what kind of output it produces.

### **& (ampersand)**

Uses the **field name found on the LHS** to build the structure on the output JSON, without requiring you to explicitly define the name on the RHS.

* **Usage:** RHS
* **Operation:** `shift`

#### **Practical example**

* **Use case:** Grouping related customer fields under a single parent object for better organization.
* **Goal:** Move existing fields into a new `client` object without renaming them.

**Input JSON**

```json
{
 "name": "Client Example",
 "email": "client-example@email.com"
}
```

**Desired output JSON**

```json
{
 "client": {
   "name": "Client Example",
   "email": "client-example@email.com"
 }
}
```

**Transformation spec**

```json
[
 {
   "operation": "shift",
   "spec": {
     "name": "client.&",
     "email": "client.&"
   }
 }
]
```

**Explanation**

This transformation moves the original `name` and `email` fields into a new `client` object.

The `&` wildcard keeps the **same field name** from the input when creating the output structure.

* `"name": "client.&"` takes the value of `name` and places it inside `client.name`.
* `"email": "client.&"` does the same for `email`, generating `client.email`.

By using `&`, you don't need to manually repeat each field name on the RHS — JOLT automatically preserves it while nesting the fields under `client`.

### **\* (asterisk)**

References **all fields or objects** without needing to explicitly list each one.

* **Usage:** LHS
* **Operations:** `shift`, `remove`, `cardinality`, `modify-default-beta`, `modify-overwrite-beta`

#### **Practical example**

* **Use case:** Organizing customer data by grouping all fields under a single parent object.
* **Goal:** Nest all fields inside a `customer` object and rename `document` to `ssn`.

**Input JSON**

```json
{
 "name": "Customer Example",
 "email": "cliente-exemplo@email.com",
 "document": "1234567890",
 "birthDate": "10/31/1990",
 "address": "Customer Example Street"
}
```

**Desired output JSON**

```json
{
 "customer": {
   "name": "Customer Example",
   "email": "client-example@email.com",
   "document": "1234567890",
   "birthDate": "10/31/1990",
   "address": "Customer Example Street"
 }
}
```

**Transformation spec**

```json
[
 {
   "operation": "shift",
   "spec": {
     "*": "customer.&",
     "document": "customer.ssn"
   }
 }
]
```

**Explanation**

In the line `"*": "customer.&"`, we take **any field found in the input JSON** and place it inside a new **customer** object, preserving both the field name and its entire structure.

For the `document` field, we take its value and map it to a new field called `ssn`, also inside the `customer` object.

**How it works:**

* `*` matches **any field**.
* `&` keeps the **original field name and value**.
* When used together (`*` + `&`), JOLT automatically copies all matched fields **without requiring you to specify them one by one**.

This combination is useful when you need to **manipulate or reorganize a JSON** without knowing its full structure in advance.

### **@ (at sign)**

References the **value** of a field.

Its behavior changes depending on the operation and whether it is used on the LHS or RHS.

* **Usage:** LHS and RHS
* **Operations:** `shift`, `modify-default-beta`, `modify-overwrite-beta`

#### **`shift` example**

* **Use case:** Dynamically creating field names based on input values.
* **Goal:** Use the value of `key` to define the field name inside `product`, assigning it the value from `value`.

**Input JSON**

```json
{  
   "key": "code",  
   "value": "123-ABC"
}
```

**Desired output JSON**

```json
{  
   "product": {    
       "code": "123-ABC"  
   }
}
```

**Transformation spec**

```json
[
 {
   "operation": "shift",
   "spec": {
     "value": "product.@(1,key)"
   }
 }
]
```

**Explanation**

In `product.@(1,key)`, the expression `@(1,key)` tells JOLT to:

* Go **one level up** (because of the `1`),
* Find the field called **`key`**,
* Use its **value (`"code"`) as the name of the new field** inside `product`.

This means the value of `"value"` (`"123-ABC"`) is assigned to a dynamically named field (`"code"`).

**How @ works:**

* `@` references data from another part of the JSON.
* The first argument (`1`) indicates **how many levels up** to look.
* The second argument (`key`) indicates **which field’s value to retrieve**.
* The same logic applies when `@` is used on the LHS or RHS of the spec.

This mechanism allows you to **dynamically create field names** based on values from the input JSON, enabling more flexible transformations.

#### **`modify-default-beta` and `modify-overwrite-beta` examples**

* **Use case:** Enriching a nested object with information stored elsewhere in the JSON.
* **Goal:** Add a `company` field inside `product`, using the value from the top-level `manufacturer` field.

**Input JSON**

```json
{
 "product": {
   "name": "Produto A",
   "price": 10
 },
 "manufacturer": "Company A"
}
```

**Desired output JSON**

```json
{
 "product": {
   "name": "Product A",
   "price": 10,
   "company": "Company A"
 },
 "manufacturer": "Company A"
}
```

**Transformation spec**

```json
[
 {
   "operation": "modify-default-beta",  //for modify-overwrite-beta 
   "spec": {                            //we'd have the same transformation
     "produto": {                       <- level 2   
       "company": "@(2,manufacturer)"   <- level 1 
     }
   }
 }
]
```

**Explanation**

We create a new field called **`company`** inside the `product` object and assign it the value of the **`manufacturer`** field.

To do this, we use `@(2,manufacturer)`, which tells JOLT to:

* Go **two levels up** (from inside `product`),
* Find the field named **`manufacturer`**,
* Retrieve **its value and assign it to `product.company`**.

**`modify-default-beta` vs. `modify-overwrite-beta`**

* **`modify-default-beta`:** Adds the `company` field **only if it doesn’t already exist** inside `product`. It preserves existing values.
* **`modify-overwrite-beta`:** Adds the `company` field **even if it already exists**, always replacing the existing value. As the name suggests, it **overwrites** any existing content.

Both operations use the same transformation spec. Only their behavior regarding overwriting differs.

### **$ (dollar sign)**

References **the name of a field** instead of its value.

* **Usage**: LHS
* **Operation**: `shift`

#### **Practical example**

* **Use case:** Identifying which fields a product object contains.
* **Goal:** Generate a list with the names of all fields inside `product`.

**Input JSON**

```json
{
 "product": {
   "name": "Product Example",
   "value": 10,
   "category": "CATEG-1",
   "weight": 25
 }
}
```

**Desired output JSON**

```json
{
 "product": [
   "name",
   "value",
   "category",
   "weight"
 ]
}
```

**Transformation spec**

```json
[
 {
   "operation": "shift",
   "spec": {
     "product": {
       "*": {
         "$": "product[]"
       }
     }
   }
 }
]
```

**Explanation**

We select all (`*`) fields inside the `product` object and use `$` to retrieve **each field’s name**, not its value. Then, we place each retrieved name into the `product[]` list.

This allows us to generate a structure that captures **only the field names** from the input JSON.

### **# (hash)**

The `#` operator has different functions depending on where it is used:

* **Usage:**
  * **LHS:** Allows inserting **manual (constant) values** into the output JSON.
  * **RHS:** Used **exclusively to create lists**, grouping content from higher levels into a new list structure.
* **Operation:** `shift`

#### **LHS example**

* **Use case:** Adding a missing field that isn’t provided in the input JSON.
* **Goal:** Insert a default `category` field inside `product` while preserving all existing fields.

**Input JSON**

```json
{ 
 "product": { 
   "name": "Product Example", 
   "value": 10, 
   "weight": 25 
 } 
}
```

**Desired output JSON**

```json
{
  "product" : {
    "category" : "DEFAULT-CATEGORY",
    "name" : "Product Example",
    "value" : 10,
    "weight" : 25
  }
}
```

**Transformation spec**

```json
[
 {
   "operation": "shift",
   "spec": {
     "product": {
       "*": "product.&",
       "#DEFAULT-CATEGORY": "product.category"
     }
   }
 }
]
```

**Explanation**

The value after the `#` wildcard (**`DEFAULT-CATEGORY`**) is **manually inserted** into the field specified in the RHS (`product.category`).

This ensures the field is always included, regardless of the input.

#### **RHS example**

* **Use case:** Standardizing field names inside an array of product objects.
* **Goal:** Rename the `value` field to `price` for every item in the `products` array.

**Input JSON**

```json
{
 "products": [
   {
     "code": "PROD-A",
     "value": 10
   },
   {
     "code": "PROD-B",
     "value": 20
   }
 ]
}
```

**Desired output JSON**

```json
{  
 "products": [
   {
     "code": "PROD-A",
     "price": 10
   },
   {
     "code": "PROD-B",
     "price": 20
   }
 ]
}
```

**Transformation spec**

```json
[
  {
    "operation": "shift",
    "spec": {
      "products": {                      // level 2
        "*": {                           // level 1
          "code": "products[#2].&",      // level 0
          "value": "products[#2].price"  // level 0
        }
      }
    }
  }
]
```

**Explanation**

Using `#` in the RHS means:

* We are **creating a list** (`[...]`).
* `#2` tells JOLT to group elements based on the structure found **two levels above**.
* This guarantees that each `code` and its corresponding `price` stay together within the same product object.

So:

* `"code": "products[#2].&"`: Takes the `code` value and places it under the `code` field inside the new `products` list.
* `"value": "products[#2].price"`: Takes the `value` field and writes it as `price` inside the same list item.

By looking **2 levels up**, JOLT preserves the original grouping of each product when forming the new list.

### **| (pipe)**

The `|` operator allows referencing **multiple possible field names** in the input JSON and mapping all of them to the **same destination** in the output JSON.

This is useful when the input structure may vary, but the output needs to remain consistent.

* **Usage:** LHS
* **Operation:** `shift`

#### **Practical example**

* **Use case:** Handling different naming conventions for the same customer field.
* **Goal:** Map either `fullName` or `customerName` to a unified `name` field.

**Input JSON**

```json
{
 "customer": {
   "fullName": "Customer Example",
   "email": "customer-example@email.com"
 }
}
```

**Desired output JSON**

```json
{
 "customer": {
   "name": "Customer Example",
   "email": "customer-example@email.com"
 }
}
```

**Transformation spec**

```json
[
 {
   "operation": "shift",
   "spec": {
     "customer": {
       "fullName|customerName": "customer.nome",
       "email": "customer.&"
     }
   }
 }
]
```

**Explanation**

* `"fullName|customerName"` means: If either `fullName` **or** `customerName` is present, its value will be assigned to `customer.name`.
* `"email": "customer.&"` preserves the field name and maps the email value as is.

This ensures the output remains consistent even when the input uses different naming conventions.

## **Continue learning**

Now that you understand how this operator works, here are a few next steps you can explore:

* [**Advanced operations**](/documentation/resources/use-cases/how-to-jolt/advanced-operations.md), where you’ll dive into more powerful transformation capabilities.
* [**Use case examples**](/documentation/resources/use-cases/how-to-jolt/use-cases.md), showing how JOLT is applied in real integration scenarios.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.digibee.com/documentation/resources/use-cases/how-to-jolt/operators.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
