> For the complete documentation index, see [llms.txt](https://docs.brigge.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.brigge.ai/documentation/brigge-for-transformers/pipelines/pipeline-nodes/merge-node.md).

# Merge node

## Introduction

The *Merge* node receives incoming datasets, performs the configured operation, and outputs a single dataset. Six merge methods are supported, each designed for a different use case depending on how you want to handle the incoming data, and the shape of output data needed:

<table data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><strong>Inner join</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FsmxQ9Od5HI7dWnZl8Wlt%2Finner%20join%201.svg?alt=media&amp;token=ae6f31f4-30d9-40e5-b512-e43429c020a7" alt=""></td></tr><tr><td><strong>Outer join</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FviQJTba9JNdRBaJ8nvv4%2Fouter%20join%201.svg?alt=media&amp;token=68227586-70e1-4f9b-ab2e-24d6e6b2c4d5" alt=""></td></tr><tr><td><strong>Left join</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FH8hLqJSzWIQ2XQE1G4Bq%2Fleft%20join%201.svg?alt=media&amp;token=143058cc-9d5a-452c-a456-a725a7f21e3b" alt=""></td></tr><tr><td><strong>Union</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2F3n6pF3kMFIzLTQdYUMYJ%2Funion.svg?alt=media&amp;token=101bb50a-e09d-4bce-b60c-c5f8e8af2091" alt=""></td></tr><tr><td><strong>Combine</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FtXwM2SLYiTDGp0HChZmR%2Fcombine%201.svg?alt=media&amp;token=cf498e7c-d632-4b4b-9ca1-9758f8f7d166" alt=""></td></tr><tr><td><strong>Insert at</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FTtHYnfpPuVbIiUcu4QMt%2Finsert%201.svg?alt=media&amp;token=73e66275-2bee-4657-87cc-30de222b23aa" alt=""></td></tr></tbody></table>

For all but two merge types ([combine](#combine) and [insert at](#insert-at)), selecting a merge method enables two input stubs (labelled `A` and `B`) on the *Merge* node, because two incoming datasets are expected:

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2F03vvnSEw3e8qK6WLhFAa%2Fmerge%20node%20inputs%20and%20output%202.png?alt=media&amp;token=3aaa9b4c-fe55-4e1b-b0bd-d4029f43561a" alt=""><figcaption></figcaption></figure></div>

These labels reflect the processing order: dataset `A` is matched against dataset `B`, and when output is assembled, dataset `B` is merged into dataset `A`. So, dataset `A` is the primary dataset.

## How is data matched for merging?

In order to merge records received from two datasets, we need a mechanism to determine how records in dataset `A` map to records in dataset `B`.

For most merge methods that *join* data from two inputs ([inner join](#inner-join), [outer join](#outer-join), [left join](#left-join)), an `input key` is defined in the *Merge* node configuration. This is a field that's common to both sets of data, and uniquely identifies each record in the dataset. For example:

{% columns %}
{% column %}
**Dataset A (employees)**

{% code overflow="wrap" %}

```json
{
  "employees": [
    {"id": 1, "name": "Alice"},
    {"id": 2, "name": "Bob"},
    {"id": 3, "name": "Charlie"}
  ]
}
```

{% endcode %}
{% endcolumn %}

{% column %}
**Dataset B (departments)**

{% code overflow="wrap" %}

```json
{
  "departments": [
    {"id": 1, "dept": "Product"},
    {"id": 3, "dept": "Finance"},
    {"id": 4, "dept": "Sales"}
  ]
}
```

{% endcode %}
{% endcolumn %}
{% endcolumns %}

Here, the `id` field is unique to each record and common to both datasets. So (depending on which merge method is selected in *Merge* node settings), we can define `id` as the `input key` and match/merge records with the same `id` number.

{% hint style="info" %}
The [union](#union) merge method also joins data from two inputs but no matching is needed.
{% endhint %}

Other merge methods ([combine](#combine) and [insert at](#insert-at)) do not match data. Instead, data is merged based on the incoming data structure.

## Sending data into a merge node

Different merge methods have different requirements in terms of how incoming data is structured.

When considering the shape of data sent into a *Merge* node, it can be helpful to think in terms of updating rows in a database. For example, suppose we are joining names and departments from two datasets, where incoming payloads contain multiple items (think multiple 'rows' or 'records'):

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FI0dFcoyVPILiXhnhMPZP%2Freceive%20data%20example.png?alt=media&amp;token=37ebf07a-d00d-4f8c-b052-2dfb8a0f8f03" alt=""><figcaption></figcaption></figure></div>

Our *Merge* node must target each individual record, which means it must either:&#x20;

* Have a mechanism to target specific records in each payload.
* Receive single-item payloads from each data stream, so a match is inherent.

As noted [previously](#how-is-data-matched-for-merging), explicit *join* methods ([inner join](#inner-join), [outer join](#outer-join), [left join](#left-join)) have the facility to match two incoming datasets on a unique key, so it's no issue if the *Merge* node receives payloads containing multiple records.

For other methods, it's advisable to use a [*Split*](/documentation/brigge-for-transformers/pipelines/pipeline-nodes/split-node.md) node upstream to batch the data into single-item payloads, before it reaches the *Merge* node.

## Merge methods

<details>

<summary>Inner join</summary>

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FsmxQ9Od5HI7dWnZl8Wlt%2Finner%20join%201.svg?alt=media&amp;token=ae6f31f4-30d9-40e5-b512-e43429c020a7" alt="" width="243"><figcaption></figcaption></figure></div>

<div align="left"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FaZM1I4ZurnyhuyE3kowA%2Fkey.svg?alt=media&amp;token=523192ae-6086-48a0-a7ea-144f3d21d915" alt=""><figcaption></figcaption></figure></div>

You provide `Input A key` and `Input B key`  fields, which are used to determine which incoming records match.

{% hint style="info" %}
For more information about field matching, see [How is data matched for merging?](#how-is-data-matched-for-merging)
{% endhint %}

Where a value in the `Input A key` matches a value in the `Input B key`, the two records are joined and output. The full `Input A` record forms the top level of the output, and the full `Input B` record (including the field used for matching) is nested under the specified `insertion key`.

Records that exist in only one data source are discarded entirely. No partial records or empty fields are output.

#### Example

The illustration below shows two incoming data sources (*Employees* and *Teams*) where `id` is the shared (`input`) key. The output is the result for an inner join:

<div data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2F6oPOs1QfvZfm3KxFOu7o%2FInner%20Join.svg?alt=media&amp;token=266b0c1d-115b-4860-bebe-79b67d520c98" alt=""><figcaption></figcaption></figure></div>

The Brigge pipeline setup for this scenario is shown below:

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><strong>Pipeline</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FSjXqKypTUKPROznBrPun%2Finner%20join%20-%20pipeline%201.png?alt=media&amp;token=026a2e25-3c9e-43c4-b505-58497a882869" alt=""></td></tr><tr><td><strong>Incoming dataset A</strong></td><td><pre class="language-json"><code class="lang-json">{
  "staff": [
    {
      "id": 1,
      "name": "Alice James"
    },
    {
      "id": 2,
      "name": "Bob Smith"
    },
    {
      "id": 3,
      "name": "Esme Fox"
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Incoming dataset B</strong></td><td><pre class="language-json"><code class="lang-json">{
  "teams": [
    {
      "id": 1,
      "team": "Jupiter"
    },
    {
      "id": 3,
      "team": "Saturn"
    },
    {
      "id": 4,
      "team": "Pluto"
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Merge node config</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FeKGH6sJXhQSYaDLWqRo2%2Finner%20join%20-%20merge%20config%201.png?alt=media&amp;token=f3ba2b84-9f9b-4695-b3a7-747d44392172" alt=""></td></tr><tr><td><strong>Success output</strong></td><td><pre class="language-json"><code class="lang-json">{
  "staff": [
    {
      "id": 1,
      "name": "Alice James",
      "work_team": {
        "id": 1,
        "team": "Jupiter"
      }
    },
    {
      "id": 3,
      "name": "Esme Fox",
      "work_team": {
        "id": 3,
        "team": "Saturn"
      }
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Failed records</strong></td><td><pre class="language-json"><code class="lang-json">[
  {
    "id": 2,
    "name": "Bob Smith"
  },
  {
    "id": 4,
    "team": "Pluto"
  }
]
</code></pre></td></tr></tbody></table>

#### Configuration

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2F597sMJZYiC9sKmGtKOaN%2Finner%20join%20config.svg?alt=media&amp;token=7fe5d24e-f8c9-4fc6-bba3-c19ddeb98c02" alt=""><figcaption></figcaption></figure></div>

Configuration options are summarised below:

<table><thead><tr><th width="227.40362548828125">Option</th><th>Summary</th></tr></thead><tbody><tr><td>Input A / B schemas</td><td>Choose a schema associated with the expected structure of payloads for both incoming datasets. Schemas are optional, but they do make defining the subsequent input keys easier.</td></tr><tr><td>Input A / B keys</td><td>Select or enter the field in both incoming data streams that should be used for matching records to be joined. This field must be unique to each record in the payload - for more information, see <a href="#how-is-data-matched-for-merging">How is data matched for merging?</a><br><br>If you have applied schemas, you can navigate the payload structure and select the required field - otherwise enter a dot notation path manually.</td></tr><tr><td>Insertion key</td><td>Sets the name of the merged object from dataset <code>B</code>.</td></tr></tbody></table>

</details>

<details>

<summary>Outer join</summary>

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FviQJTba9JNdRBaJ8nvv4%2Fouter%20join%201.svg?alt=media&amp;token=68227586-70e1-4f9b-ab2e-24d6e6b2c4d5" alt="" width="243"><figcaption></figcaption></figure></div>

<div align="left"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FaZM1I4ZurnyhuyE3kowA%2Fkey.svg?alt=media&amp;token=523192ae-6086-48a0-a7ea-144f3d21d915" alt=""><figcaption></figcaption></figure></div>

You provide `Input A key` and `Input B key`  fields, which are used to determine which incoming records match.

{% hint style="info" %}
For more information about field matching, see [How is data matched for merging?](#how-is-data-matched-for-merging)
{% endhint %}

Where a value in the `Input A key` matches a value in the `Input B key`, the two records are joined and output. The full `Input A` record forms the top level of the output, and the full `Input B` record (including the field used for matching) is nested under the specified `insertion key`.

Additionally:

* If dataset `A` (the left input) has no match in dataset `B`, it is output on its own.
* If dataset `B` (the right input) has no match in dataset `A`, it is output on its own.

#### Example

The illustration below shows two incoming data sources (*Employees* and *Departments*) where `id` is the shared (`input`) key:

<div data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FjDuOwGRFn80qTu3PY0Da%2FOuter%20join.svg?alt=media&amp;token=fe60f3da-e75b-4813-91f4-b5fe52f551e5" alt=""><figcaption></figcaption></figure></div>

The Brigge pipeline setup for this scenario is shown below:

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><strong>Pipeline</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FjTmdt0inQR64e65d115t%2Fouter%20join%20pipeline.png?alt=media&amp;token=82f3882c-6472-4872-b0f7-c236e80e55b7" alt=""></td></tr><tr><td><strong>Incoming dataset A</strong></td><td><pre class="language-json"><code class="lang-json">{
  "staff": [
    {
      "id": 1,
      "name": "Alice James"
    },
    {
      "id": 2,
      "name": "Bob Smith"
    },
    {
      "id": 3,
      "name": "Esme Fox"
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Incoming dataset B</strong></td><td><pre class="language-json"><code class="lang-json">{
  "teams": [
    {
      "id": 1,
      "team": "Jupiter"
    },
    {
      "id": 3,
      "team": "Saturn"
    },
    {
      "id": 4,
      "team": "Pluto"
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Merge node config</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FLnMHFx1SLa906vv90pc2%2Fouter%20join%20merge%20config.png?alt=media&amp;token=866220f4-680f-49b9-8982-830abe092830" alt=""></td></tr><tr><td><strong>Success output</strong></td><td><pre class="language-json"><code class="lang-json">{
  "staff": [
    {
      "id": 1,
      "name": "Alice James",
      "work_team": {
        "id": 1,
        "team": "Jupiter"
      }
    },
    {
      "id": 2,
      "name": "Bob Smith",
      "work_team": {
        "id": 2
      }
    },
    {
      "id": 3,
      "name": "Esme Fox",
      "work_team": {
        "id": 3,
        "team": "Saturn"
      }
    },
    {
      "id": 4,
      "work_team": {
        "id": 4,
        "team": "Pluto"
      }
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Failed records</strong></td><td>None - all records output successfully.</td></tr></tbody></table>

#### Configuration

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FHLmqe2S0H0pzeUZeWlqN%2Fouter%20join%20config.svg?alt=media&amp;token=c5b2f003-c1bb-4470-b760-e9a2fb450e4b" alt=""><figcaption></figcaption></figure></div>

Configuration options are summarised below:

<table><thead><tr><th width="227.40362548828125">Option</th><th>Summary</th></tr></thead><tbody><tr><td>Input A / B schemas</td><td>Choose a schema associated with the expected structure of payloads for both incoming datasets. Schemas are optional, but they do make defining the subsequent input keys easier.</td></tr><tr><td>Input A / B keys</td><td>Select or enter the field in both incoming data streams that should be used for matching records to be joined. This field must be unique to each record in the payload - for more information, see <a href="#how-is-data-matched-for-merging">How is data matched for merging?</a><br><br>If you have applied schemas, you can navigate the payload structure and select the required field - otherwise enter a dot notation path manually.</td></tr><tr><td>Insertion key</td><td>Sets the name of the merged object from dataset <code>B</code>.</td></tr></tbody></table>

</details>

<details>

<summary>Left join</summary>

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FH8hLqJSzWIQ2XQE1G4Bq%2Fleft%20join%201.svg?alt=media&amp;token=143058cc-9d5a-452c-a456-a725a7f21e3b" alt="" width="243"><figcaption></figcaption></figure></div>

<div align="left"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FaZM1I4ZurnyhuyE3kowA%2Fkey.svg?alt=media&amp;token=523192ae-6086-48a0-a7ea-144f3d21d915" alt=""><figcaption></figcaption></figure></div>

You provide an `Input A key` and `Input B key`  fields, which are used to determine which incoming records match.

{% hint style="info" %}
For more information about field matching, see [How is data matched for merging?](#how-is-data-matched-for-merging)
{% endhint %}

If a matching `input key` is found in both data sources, the data is joined and output. Also:

* If dataset `A` (the left input) has no match in dataset `B`, it is output on its own. &#x20;
* If dataset `B` (the right input) has no match in dataset `A`, it is discarded.

In short, dataset `A` is always output, irrespective of whether a join can be made.

#### Example

The illustration below shows two incoming data sources (*Employees* and *Departments*) where `id` is the shared (`input`) key:

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FH3Ob5hmBoMDbXrUdWYgW%2FLeft%20join.svg?alt=media&amp;token=300b5951-37c0-4130-9964-3b47187b2486" alt=""><figcaption></figcaption></figure></div>

The Brigge pipeline setup for this scenario is shown below:

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><strong>Pipeline</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FnaD0yp6ChlEBqTrVSp1d%2Fleft%20join%20pipeline.png?alt=media&amp;token=000873f7-1b98-4e32-82b7-6324c7ebd511" alt=""></td></tr><tr><td><strong>Incoming dataset A</strong></td><td><pre class="language-json"><code class="lang-json">{
  "staff": [
    {
      "id": 1,
      "name": "Alice James"
    },
    {
      "id": 2,
      "name": "Bob Smith"
    },
    {
      "id": 3,
      "name": "Esme Fox"
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Incoming dataset B</strong></td><td><pre class="language-json"><code class="lang-json">{
  "teams": [
    {
      "id": 1,
      "team": "Jupiter"
    },
    {
      "id": 3,
      "team": "Saturn"
    },
    {
      "id": 4,
      "team": "Pluto"
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Merge node config</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FYx75UKjKD7mrpVtbL18i%2Fleft%20join%20merge%20config.png?alt=media&amp;token=52be2abc-fbe3-4af0-9349-e5c3217c05fa" alt=""></td></tr><tr><td><strong>Success output</strong></td><td><pre class="language-json"><code class="lang-json">{
  "staff": [
    {
      "id": 1,
      "name": "Alice James",
      "team": {
        "id": 1,
        "team": "Jupiter"
      }
    },
    {
      "id": 2,
      "name": "Bob Smith"
    },
    {
      "id": 3,
      "name": "Esme Fox",
      "team": {
        "id": 3,
        "team": "Saturn"
      }
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Failed records</strong></td><td><pre class="language-json"><code class="lang-json">[
  {
    "id": 4,
    "team": "Pluto"
  }
]
</code></pre></td></tr></tbody></table>

#### Configuration

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2Fgj3G0XS2QrG40nEWlqDW%2Fleft%20join%20config.svg?alt=media&amp;token=ff135a5f-9b85-44f9-8076-883ae9e2c826" alt=""><figcaption></figcaption></figure></div>

Configuration options are summarised below:

<table><thead><tr><th width="227.40362548828125">Option</th><th>Summary</th></tr></thead><tbody><tr><td>Input A / B schemas</td><td>Choose a schema associated with the expected structure of payloads for both incoming datasets. Schemas are optional, but they do make defining the subsequent input keys easier.</td></tr><tr><td>Input A / B keys</td><td>Select or enter the field in both incoming data streams that should be used for matching records to be joined. This field must be unique to each record in the payload - for more information, see <a href="#how-is-data-matched-for-merging">How is data matched for merging?</a><br><br>If you have applied schemas, you can navigate the payload structure and select the required field - otherwise enter a dot notation path manually.</td></tr><tr><td>Insertion key</td><td>Sets the name of the merged object from dataset <code>B</code>.</td></tr></tbody></table>

</details>

<details>

<summary>Union</summary>

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FECzQR5LlRksA3Pe0uF8E%2Funion.svg?alt=media&amp;token=90914646-a547-449d-9e06-13863e1467e2" alt=""><figcaption></figcaption></figure></div>

Stacks incoming (array) datasets into a single flat output array within a named JSON object - dataset `A` followed by `B`. There is no matching, pairing, or key comparison.

#### Example

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><strong>Pipeline</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FhipxuQGXqTopouIl675e%2Funion%20pipeline%201.png?alt=media&amp;token=95d95296-fe5d-432d-95b1-2bce73dd669f" alt=""></td></tr><tr><td><strong>Incoming dataset A</strong></td><td><pre class="language-json"><code class="lang-json">{
  "staff": [
    {
      "id": 1,
      "name": "Alice James"
    },
    {
      "id": 2,
      "name": "Bob Smith"
    },
    {
      "id": 3,
      "name": "Esme Fox"
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Incoming dataset B</strong></td><td><pre class="language-json"><code class="lang-json">{
  "staff": [
    {
      "id": 1,
      "name": "Polly Lowe"
    },
    {
      "id": 2,
      "name": "Mia Fey"
    },
    {
      "id": 3,
      "name": "Paul Binns"
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Merge node config</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FfDjb6ALTYCU83UfVd6pS%2Funion%20merge%20node%20config.png?alt=media&amp;token=2f898622-ee54-42a0-a85f-581b71a16ab9" alt=""></td></tr><tr><td><strong>Success output</strong></td><td><pre class="language-json"><code class="lang-json">{
  "forenames": [
    {
      "id": 1,
      "name": "Alice James"
    },
    {
      "id": 2,
      "name": "Bob Smith"
    },
    {
      "id": 3,
      "name": "Esme Fox"
    },
    {
      "id": 1,
      "name": "Polly Lowe"
    },
    {
      "id": 2,
      "name": "Mia Fey"
    },
    {
      "id": 3,
      "name": "Paul Binns"
    }
  ]
}
</code></pre></td></tr><tr><td><strong>Failed records</strong></td><td>None - all records output successfully.</td></tr></tbody></table>

#### Configuration

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FqP16lcFg5xHDO1Ysfm4Y%2FUnion%20config.svg?alt=media&amp;token=a3606c9b-7c9c-4e1f-a751-3a7020666588" alt=""><figcaption></figcaption></figure></div>

Configuration options are summarised below:

<table><thead><tr><th width="227.40362548828125">Option</th><th>Summary</th></tr></thead><tbody><tr><td>Input A / B schemas</td><td>Choose a schema associated with the expected structure of payloads for both incoming datasets. Schemas are optional, but they do make defining the subsequent input keys easier.</td></tr><tr><td>Input A / B keys</td><td>Select or enter the (array) field name from the incoming payload whose values you want to output. If you have applied a schema, you can navigate the payload structure and select the required field - otherwise enter a dot notation path manually.</td></tr><tr><td>Insertion key</td><td>Sets the name of the output object.</td></tr></tbody></table>

</details>

<details>

<summary>Combine</summary>

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2Fmgc51Jgxx0NvEKTnyDRO%2FCombine.svg?alt=media&amp;token=fb30c69a-ec29-48d9-a2f5-9cadecc3a3b6" alt=""><figcaption></figcaption></figure></div>

Collects the values for a specified field from each incoming payload and outputs them in a single array. There is no matching, pairing, or key comparison.

#### Configuration

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FxRwQuYjRAwlrKRGONboT%2Fcombine%20config.svg?alt=media&amp;token=7063d66d-6afc-47bb-93a9-afa722382f42" alt=""><figcaption></figcaption></figure></div>

Configuration options are summarised below:

<table><thead><tr><th width="227.40362548828125">Option</th><th>Summary</th></tr></thead><tbody><tr><td>Input A schema</td><td>Choose a schema associated with the expected structure of incoming payloads. This setting is optional - it just makes defining the subsequent <code>input A key</code> easier.</td></tr><tr><td>Input A key</td><td>Select or enter the field name from the incoming payload whose values you want collected into the output array. If you have applied a schema, you can navigate the payload structure and select the required field - otherwise enter a dot notation path manually.</td></tr><tr><td>Insertion key</td><td>Sets the name of the output array.</td></tr></tbody></table>

#### Example

Suppose a *Merge* node receives multiple, single-item payloads for employee details:

{% code overflow="wrap" %}

```json
{"id":1,"first":"Alice","last":"Johnson","hours_worked":38}
```

{% endcode %}

{% code overflow="wrap" %}

```json
{"id":2,"first":"Bob","last":"Smith","hours_worked":42}
```

{% endcode %}

{% code overflow="wrap" %}

```json
{"id":3,"first":"Charlie","last":"Davis","hours_worked":40}
```

{% endcode %}

Using the `combine` option, we can output all received `hours_worked` values into an array, within a named JSON object. For example:

{% code overflow="wrap" %}

```json
{"to_invoice":[38,42,40,35,45]}
```

{% endcode %}

The Brigge pipeline setup for this scenario is shown below:

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th></tr></thead><tbody><tr><td><strong>Pipeline</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FKsHnaMqMkTJ4aMEk68l0%2Fcombine%20pipeline.png?alt=media&amp;token=d5bfbc38-7249-4246-b628-ce2f8d9289e5" alt=""></td></tr><tr><td><strong>Incoming dataset A</strong></td><td><pre class="language-json"><code class="lang-json">{
  "hours": [
    {"id": 1, "first": "Alice", "last": "Johnson", "hours_worked": 38},
    {"id": 2, "first": "Bob", "last": "Smith", "hours_worked": 42},
    {"id": 3, "first": "Charlie", "last": "Davis", "hours_worked": 40},
    {"id": 4, "first": "Diana", "last": "Moore", "hours_worked": 35},
    {"id": 5, "first": "Jack", "last": "Brown", "hours_worked": 45}
  ]
}
</code></pre></td></tr><tr><td><strong>Split node</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FPZIJOc24snc3NSt6cnNV%2Fcombine%20pipeline%20-%20split.png?alt=media&amp;token=cbefdc27-fc1b-479c-bbfc-6755a66d63cb" alt=""></td></tr><tr><td><strong>Merge node config</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FfDjb6ALTYCU83UfVd6pS%2Funion%20merge%20node%20config.png?alt=media&amp;token=2f898622-ee54-42a0-a85f-581b71a16ab9" alt=""></td></tr><tr><td><strong>Success output</strong></td><td><pre class="language-json"><code class="lang-json">{"hours_to_invoice":[38,42,40,35,45]}
</code></pre></td></tr><tr><td><strong>Failed records</strong></td><td>None - all records output successfully.</td></tr></tbody></table>

</details>

<details>

<summary>Insert at</summary>

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2F1wsPyB7LFX623zjRjqkR%2Finsert%201.svg?alt=media&amp;token=7b2eb163-c932-41fb-86bf-4f4a54bd3485" alt=""><figcaption></figcaption></figure></div>

Injects a field value from dataset `B` into dataset `A` at a specified position. There is no matching - dataset `B` exists purely as a source to extract a value from.

{% hint style="info" %}
When inserting data, it's advisable to use a [*Split*](/documentation/brigge-for-transformers/pipelines/pipeline-nodes/split-node.md) node upstream to batch the data into single-item payloads, before it reaches the *Merge* node. For more information, see [Sending data into a merge node](#sending-data-into-a-merge-node).
{% endhint %}

#### Configuration

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FqllkoSzuOc7HhcrtjhdW%2FInsert%20at%20config.svg?alt=media&amp;token=bc8d0a35-d9ab-4f0d-a61f-7a644894384f" alt=""><figcaption></figcaption></figure></div>

Configuration options are summarised below:

<table><thead><tr><th width="227.40362548828125">Option</th><th>Summary</th></tr></thead><tbody><tr><td>Input A / B schemas</td><td>Choose a schema associated with the expected structure of payloads for both incoming datasets. Schemas are optional, but they do make defining the subsequent <code>insert</code> and <code>input</code> keys easier.</td></tr><tr><td>Insert at</td><td>Determines the insert position within dataset <code>A</code>. The input from dataset <code>B</code> is inserted immediately after the field named here.</td></tr><tr><td>Input B key</td><td>Determines which field to collect from dataset <code>B</code>; any other fields in dataset <code>B</code> are ignored.</td></tr><tr><td>Insertion key</td><td>Sets the name of the output object.</td></tr></tbody></table>

#### Example

Suppose dataset `A` includes employee names and countries:

{% code overflow="wrap" %}

```json
{"name": "Alice Jones", "country": "UK"}
```

{% endcode %}

...and dataset `B` includes billing details for employees:

{% code overflow="wrap" %}

```json
{"currency1": "GBP","currency2": "USD","currency3": "EUR"}
```

{% endcode %}

We can use the `insert at` method to inject the relevant currency field from dataset `B` into dataset A:

{% code overflow="wrap" %}

```json
{"name": "Alice Jones",  "country": "UK",  "currency": "GBP"}
```

{% endcode %}

The Brigge pipeline setup for this scenario is shown below:

<table data-card-size="large" data-view="cards"><thead><tr><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td><strong>Pipeline</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FbfqaqZlMsj5NXwci8dfs%2Finsert%20pipeline.png?alt=media&amp;token=9aa01895-8f35-4032-8d28-6da33d52f607" alt=""></td><td></td><td></td></tr><tr><td><strong>Incoming dataset A</strong></td><td><pre class="language-json"><code class="lang-json">{
  "employees": [
    {"name": "Alice Jones","country": "UK" },
    {"name": "Bob Smith","country": "USA"},
    {"name": "Charlie Pink","country": "EU" }
  ]
}

</code></pre></td><td></td><td></td></tr><tr><td><strong>Incoming dataset B</strong></td><td><pre class="language-json"><code class="lang-json">{
"currencies": \[
{ "currency": "GBP"},
{ "currency": "USD"},
{ "currency": "EUR" }
]
} </code></pre></td><td></td><td></td></tr><tr><td><strong>Split node (dataset A)</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FbVdgTy0drtBIDUq1ZA1H%2Finsert%20-%20split%201.png?alt=media&amp;token=a61c997c-1218-4aaa-a79c-89c8d1d2de5e" alt=""></td><td></td><td></td></tr><tr><td><strong>Split node (dataset B)</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FMZNCFj57Fhhyf5vFAkGU%2Finsert%20-%20split%202.png?alt=media&amp;token=f087e5bc-a5cf-43fb-8237-8f3779046c60" alt=""></td><td></td><td></td></tr><tr><td><strong>Merge node config</strong></td><td><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FUaRgzBu7Kks8OSdPsT0I%2Finsert%20merge%20config.png?alt=media&amp;token=06e9a10e-7128-46d1-a654-96aa0c19ee2e" alt=""></td><td></td><td></td></tr><tr><td><strong>Success output</strong></td><td><pre class="language-json"><code class="lang-json">{"name":"Alice Jones","country":"UK","currency":"GBP"} </code></pre></td><td><pre class="language-json"><code class="lang-json">{"name":"Bob Smith","country":"USA","currency":"USD"} </code></pre></td><td><pre class="language-json"><code class="lang-json">{"name":"Charlie Pink","country":"EU","currency":"EUR"} </code></pre></td></tr><tr><td><strong>Failed records</strong></td><td>None - all records output successfully.</td><td></td><td></td></tr></tbody></table>

{% hint style="info" %}
Incoming datasets (each containing one record) arrive in the same order. Each currency record in dataset `B` corresponds positionally to the employee record in dataset `A`.
{% endhint %}

</details>

## Error handling

When using a merge method that joins records from two incoming datasets, there are scenarios where some records can be merged but others can't. For example, the [inner join](#inner-join) method will only merge records where a match is found in *both* incoming datasets. If a record is present in dataset `A` that is not matched in `B`, the `A` record is discarded (and vice versa).

With this in mind, enabling manual error handling for *Merge* nodes is recommended. To do this, edit the *Merge* node and click the `advanced settings` (cog) icon in the title bar for *Advanced Settings*, then toggle `handle errors manually` to `on`:

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FSoeldFHF5tOVGGJrxm8w%2FMerge%20node%20-%20error%20handling.svg?alt=media&amp;token=c33132c0-ff3e-4008-bd98-ff17b49fcdae" alt="" width="523"><figcaption></figcaption></figure></div>

This activates 'success' and 'fail' stubs from the *Merge* node, so you can define different paths for successful outcomes and failed outcomes. For example:

<div align="left" data-with-frame="true"><figure><img src="https://2172380191-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8IqdqwZowcxtFpZfLa6k%2Fuploads%2FdNfaLZnWjb8VV40lZ971%2Fmanual%20error%20handling%20stubs.png?alt=media&amp;token=3374cbbc-6aa9-4a08-93be-4a0cce8cbbde" alt=""><figcaption></figcaption></figure></div>

This means:

* Non-merged records do not cause the pipeline to fail.
* Non-merged records are output as `failed` payloads in [run logs](/documentation/brigge-for-operators/history-and-retries.md).
