Merge (append) in Schleife

Hello n8n community!

I have searched the documentation but did not find a successful answer to my problem.

The use case

I’m processing a list of customer records. Each customer has a contacts array containing items of different types (e.g. phone, email). My goal is to:

  1. Split the contacts array into individual items
  2. Apply a different mapping depending on the contact type (e.g. phone numbers need to be parsed and reformatted, emails pass through directly)
  3. Re-aggregate all mapped contacts back into a single array
  4. Merge that array back into the original customer item to build the final payload

The workflow

The Merge (append) node works inside a loop when the Aggregate is the last node. However, adding a Merge (combine by position) after the Aggregate — which is necessary to reassemble the contacts back into the customer item — breaks the loop entirely.

Test data:

{
  "data": [{
  "firstName": "John",
  "lastName": "Doe",
  "contacts": [
    {
      "type": "phone",
      "value": "+33652252525"
    }
  ]
},
{
  "firstName": "Mary",
  "lastName": "Doe",
  "contacts": [
    {
      "type": "email",
      "value": "marydoe@example.com"
    }
  ]
},
  {
  "firstName": "John",
  "lastName": "Smith",
  "contacts": [
    {
      "type": "email",
      "value": "johnsmith@example.com"
    },
      {
      "type": "phone",
      "value": "+33652252526"
    }
  ]
}]
}


Workflow

Information on your n8n setup

  • n8n version: 2.20.9
  • Database (default: SQLite): PostgrSQL
  • Running n8n via (Docker, npm, n8n cloud, desktop app): Docker

Willkommen @thomaslc in unserer Community! Ich bin Jay und ich bin ein n8n verified creator.

Der Merge (combine by position) Node innerhalb einer SplitInBatches-Schleife funktioniert nicht, weil er erwartet, dass zwei Eingaben gleichzeitig ankommen - aber innerhalb einer Schleife ist pro Iteration nur ein Branch aktiv. Das ist nicht für dieses Muster ausgelegt.

Die sauberste Lösung ist hier, die innere Schleife + Merge komplett zu überspringen und die gesamte Kontakttransformation in einem einzigen Code Node pro Kunde zu handhaben. Etwa so:

const contacts = $json.contacts;
const mapped = contacts.map(c => {
  if (c.type === 'phone') {
    return { type: 'phone', value: c.value.replace(/\s/g, '') };
  }
  return c;
});
return [{ json: { ...$json, contacts: mapped } }];

Das läuft pro Element in deiner äußeren Schleife, transformiert das contacts-Array direkt und speist es direkt in deine finale Payload ein - keine innere Schleife oder Merge nötig.

Interessante Einschränkung. Du könntest den Workflow mit einem Code-Node vereinfachen (wie zuvor beantwortet) oder sogar einen Edit Fields-Node mit etwas JS verwenden. Eine weitere Option ist, die Schleifenfunktionalität in einen Sub-Workflow zu übergeben und die Sub-Workflow-Ausgabe zusammenzuführen.

Der sauberste Weg, um dies zu handhaben, ist ein einzelner Code-Node, der alle vier Schritte auf einmal ausführt und die Schleife vollständig überspringt:

return items.map(item => {
  const mapped = item.json.contacts.map(c => {
    if (c.type === 'phone') return { ...c, value: c.value.replace(/\D/g, '') };
    return c; // email passes through
  });
  return { json: { ...item.json, contacts: mapped } };
});

Dies vermeidet den Loop-Merge-Konflikt, da du das Array inline transformierst. Das Merge (combine by position) bricht die Schleife – dies ist zu erwarten, da n8n-Schleifen die Mid-Loop-Aggregation nicht gut handhaben. Wenn du den Node-basierten Ansatz beibehalten möchtest, übergib jeden verarbeiteten Kunden über Execute Workflow an einen Sub-Workflow und aggregiere die Ergebnisse nach Abschluss aller Ausführungen.

Hallo @nguyenthieutoan, @njogued

Danke für dein Feedback! Der Grund, warum ich eine Schleife verwende, ist, dass ich benutzerdefinierte Knoten wie einen Phone-Checker-Knoten nutze. Ein Code-Knoten könnte das nicht ersetzen.

What ich am Ende gemacht habe, war einen Sub-Workflow zu erstellen, der mit der Option “Einmal für jedes Element ausführen” aufgerufen wird.

hi @thomaslc , willkommen!

ich habe mir die dokumentation zu diesen elementen angeschaut, und meines verständnis nach hat das damit zu tun, wie n8n den kontext des elements beibehält. wenn du Split Out, Loop Over Items, Merge und Aggregate verwendest, muss er die verbindung zwischen jedem aggregierten kontakt und dem original-customer bewahren oder wiederherstellen. Merge combine by position kann diese logik durcheinander bringen, wenn die menge oder reihenfolge der elemente nicht exakt gleich ist.

hier sind die docs, die dir helfen werden: