n8nen.nl logo n8nen.nl

N8N Merge Node: Data Streams Combineren als een Pro

2025-01-29 Sam Stroobandt
N8N Merge Node: Data Streams Combineren als een Pro
Input 1Customer Data500 itemsInput 2Order Data1200 itemsMERGENodeAppendCombineSQLKeep MatchesInner JoinKeep EverythingOuter JoinEnrich Input 1Left JoinMultiplexAll CombinationsOutputMerged DataVariable itemsMultiple SourcesMerge StrategyOutput OptionsCombined Result

Waarom de Merge Node Onmisbaar is

In de echte wereld komt data zelden uit één bron. Je hebt klantgegevens in je CRM, bestellingen in je webshop, voorraad in je ERP, en reviews op externe platformen. De Merge node is de lijm die al deze data streams samenbrengt tot één coherent geheel.

Of je nu een simpele lijst wilt samenvoegen of complexe SQL joins moet uitvoeren tussen datasets, de Merge node heeft de tools die je nodig hebt. Met support voor tot onbeperkt aantal inputs sinds versie 1.49.0 en krachtige SQL query mogelijkheden, is dit een van de meest veelzijdige nodes in N8N.

De 4 Merge Modes: Van Simpel tot Complex

Mode 1: Append (Keep All Data) 📋

De simpelste vorm - voeg alle data samen, item voor item:

// Input 1: 3 customers
[
  { id: 1, name: "Jan", city: "Amsterdam" },
  { id: 2, name: "Piet", city: "Rotterdam" },
  { id: 3, name: "Klaas", city: "Utrecht" }
]

// Input 2: 2 suppliers
[
  { id: 101, company: "TechCo", product: "Software" },
  { id: 102, company: "DataCorp", product: "Analytics" }
]

// Output (Append): 5 items totaal
[
  { id: 1, name: "Jan", city: "Amsterdam" },
  { id: 2, name: "Piet", city: "Rotterdam" },
  { id: 3, name: "Klaas", city: "Utrecht" },
  { id: 101, company: "TechCo", product: "Software" },
  { id: 102, company: "DataCorp", product: "Analytics" }
]

Use Cases:

  • Consolideren van multiple data sources
  • Aggregeren van resultaten van parallelle branches
  • Verzamelen van data voor reporting

Mode 2: Combine - De Powerhouse 🔄

De meest flexibele mode met 3 combine strategieën:

A. Combine by Fields (Database Joins)

Output TypeSQL EquivalentBeschrijvingUse Case
Keep MatchesINNER JOINAlleen matching itemsOrder-customer koppeling
Keep Non-MatchesANTI JOINAlleen non-matchingVind ontbrekende data
Keep EverythingFULL OUTER JOINAlle itemsComplete dataset
Enrich Input 1LEFT JOINInput 1 + matchesVerrijk hoofddata
Enrich Input 2RIGHT JOINInput 2 + matchesVerrijk secundaire data
// Praktijkvoorbeeld: Customer enrichment met orders

// Input 1: Customers
[
  { customerId: 1, name: "Jan", email: "jan@example.com" },
  { customerId: 2, name: "Piet", email: "piet@example.com" },
  { customerId: 3, name: "Klaas", email: "klaas@example.com" }
]

// Input 2: Orders
[
  { orderId: 101, customerId: 1, amount: 150.00 },
  { orderId: 102, customerId: 1, amount: 75.50 },
  { orderId: 103, customerId: 2, amount: 200.00 }
]

// Merge Settings:
Mode: Combine
Combine By: Matching Fields
Fields to Match:
  Input 1 Field: customerId
  Input 2 Field: customerId
Output: Enrich Input 1

// Output: Customers enriched met order data
[
  { 
    customerId: 1, 
    name: "Jan", 
    email: "jan@example.com",
    orderId: 101,
    amount: 150.00
  },
  { 
    customerId: 1, 
    name: "Jan", 
    email: "jan@example.com",
    orderId: 102,
    amount: 75.50
  },
  { 
    customerId: 2, 
    name: "Piet", 
    email: "piet@example.com",
    orderId: 103,
    amount: 200.00
  },
  { 
    customerId: 3, 
    name: "Klaas", 
    email: "klaas@example.com"
    // Geen orders - maar customer blijft behouden
  }
]

B. Combine by Position (Index-based)

// Merge items op basis van hun positie in de array

// Input 1: Product names
[
  { product: "Laptop" },
  { product: "Mouse" },
  { product: "Keyboard" }
]

// Input 2: Prices
[
  { price: 999.99 },
  { price: 29.99 },
  { price: 79.99 }
]

// Output: Position-based merge
[
  { product: "Laptop", price: 999.99 },      // Index 0 + 0
  { product: "Mouse", price: 29.99 },        // Index 1 + 1
  { product: "Keyboard", price: 79.99 }      // Index 2 + 2
]

C. Multiplex (All Possible Combinations)

// Genereer alle mogelijke combinaties (Cartesian Product)

// Input 1: Sizes
[
  { size: "S" },
  { size: "M" },
  { size: "L" }
]

// Input 2: Colors
[
  { color: "Red" },
  { color: "Blue" }
]

// Output: All combinations (3 x 2 = 6 items)
[
  { size: "S", color: "Red" },
  { size: "S", color: "Blue" },
  { size: "M", color: "Red" },
  { size: "M", color: "Blue" },
  { size: "L", color: "Red" },
  { size: "L", color: "Blue" }
]

Mode 3: Choose Branch 🚦

Selecteer welke input branch je wilt gebruiken:

// Conditionele branch selection

// Settings:
Mode: Choose Branch
Output: Input 2  // Kies specifieke input

// Use case: A/B testing of fallback scenarios
if (testCondition) {
  // Use Input 1: Production data
  return input1;
} else {
  // Use Input 2: Test data
  return input2;
}

Mode 4: SQL Query (Advanced) 🔍

Sinds versie 1.49.0 - gebruik SQL voor complexe merges:

-- SQL Mode met multiple inputs
-- Input tables: input1, input2, input3, etc.

-- Voorbeeld 1: Complex join met aggregatie
SELECT 
  c.customerId,
  c.name,
  c.email,
  COUNT(o.orderId) as totalOrders,
  SUM(o.amount) as totalSpent,
  AVG(o.amount) as avgOrderValue
FROM input1 c
LEFT JOIN input2 o ON c.customerId = o.customerId
GROUP BY c.customerId, c.name, c.email
ORDER BY totalSpent DESC;

-- Voorbeeld 2: Union met filtering
SELECT 'Customer' as type, name, email, city 
FROM input1 
WHERE active = true
UNION ALL
SELECT 'Supplier' as type, company as name, contact as email, location as city
FROM input2
WHERE verified = true;

-- Voorbeeld 3: Window functions
SELECT 
  *,
  ROW_NUMBER() OVER (PARTITION BY category ORDER BY price DESC) as rank,
  SUM(quantity) OVER (PARTITION BY category) as categoryTotal
FROM input1;

Advanced Options & Settings

Clash Handling

Wat gebeurt er als beide inputs dezelfde field names hebben?

OptionGedragResultaat
Always Add Input NumberVoeg input nummer toe aan alle fieldsname_1, name_2
Prefer Input 1 VersionGebruik waarde van Input 1Input 1 overwint
Prefer Input 2 VersionGebruik waarde van Input 2Input 2 overwint

Additional Options

  • Fuzzy Compare: Behandel "3" en 3 als gelijk
  • Disable Dot Notation: Voorkom parent.child field access
  • Multiple Matches: Bepaal hoe om te gaan met meerdere matches
  • Include Unpaired Items: Behoud items zonder match

Praktijkvoorbeeld: Complete E-commerce Data Pipeline

ShopifyProductsGoogle SheetsInventoryMySQLCustomersAPIReviewsMerge 1Products + InventoryEnrich by SKUMerge 2+ CustomersLeft JoinMerge 3+ ReviewsAggregate & EnrichComplete DatasetAll Data MergedReady for AnalysisPipeline ConfigurationStep 1: Combine by SKUMatch products with stockStep 2: Enrich with customersAdd purchase historyStep 3: Add review scoresCalculate averagesOutput: 360° viewComplete product insights
// Complete e-commerce data merge workflow

// Step 1: Products + Inventory merge
const merge1Config = {
  mode: 'Combine',
  combineBy: 'Matching Fields',
  field1: 'sku',          // Shopify SKU
  field2: 'product_code', // Google Sheets code
  output: 'Enrich Input 1',
  options: {
    fuzzyCompare: true,
    multipleMatches: 'Include All Matches'
  }
};

// Output: Products met real-time voorraad
const enrichedProducts = [
  {
    sku: "LAPTOP-001",
    title: "Gaming Laptop",
    price: 1299.99,
    stock_quantity: 15,     // Van Google Sheets
    warehouse: "Amsterdam",  // Van Google Sheets
    reorder_point: 5        // Van Google Sheets
  }
  // ... meer producten
];

// Step 2: Add customer purchase data
const merge2Config = {
  mode: 'SQL Query',
  query: `
    SELECT 
      p.*,
      COUNT(DISTINCT c.customerId) as unique_buyers,
      SUM(c.quantity) as total_sold,
      AVG(c.order_value) as avg_order_value
    FROM input1 p
    LEFT JOIN input2 c ON p.sku = c.product_sku
    GROUP BY p.sku
  `
};

// Step 3: Add review aggregates
const merge3Config = {
  mode: 'Combine',
  combineBy: 'Matching Fields',
  field1: 'sku',
  field2: 'product_id',
  output: 'Enrich Input 1',
  additionalOptions: {
    includeUnpaired: true  // Producten zonder reviews behouden
  }
};

// Final output: Complete 360° product view
const finalDataset = [
  {
    sku: "LAPTOP-001",
    title: "Gaming Laptop",
    price: 1299.99,
    stock_quantity: 15,
    warehouse: "Amsterdam",
    unique_buyers: 45,
    total_sold: 52,
    avg_order_value: 1450.50,
    review_count: 38,
    avg_rating: 4.7,
    recommendation_rate: 0.92
  }
  // Complete dataset voor analyse
];

Performance Optimalisatie

Memory Management bij Grote Datasets

Dataset SizeRecommended ModeOptimization Tips
< 1000 itemsAny modeNo optimization needed
1000-10,000 itemsCombine with indexingUse field matching, avoid multiplex
10,000-50,000 itemsSQL modeUse indexes, limit columns
> 50,000 itemsSplit & batch mergeUse Loop Over Items eerst

Best Practices

  • Index je match fields: Sorteer data op merge fields voor snellere matching
  • Limit columns: Selecteer alleen benodigde fields vóór merge
  • Avoid multiplex bij grote sets: Cartesian products exploderen snel
  • Use SQL voor complexe logic: Efficiënter dan multiple merge nodes
  • Monitor execution time: Check N8N execution logs

Common Use Cases & Patterns

1. Customer 360° View

// Merge customer data van alle touchpoints
Workflow:
1. CRM data (Input 1)
2. E-commerce orders (Input 2) 
3. Support tickets (Input 3)
4. Email engagement (Input 4)

// Merge strategy:
- Merge 1+2: Enrich customers met orders
- Merge result+3: Add support history
- Merge result+4: Add engagement metrics
- Output: Complete customer profile

2. Inventory Reconciliation

// Vergelijk voorraad tussen systemen
Workflow:
1. ERP inventory (Input 1)
2. Warehouse scans (Input 2)
3. Webshop stock (Input 3)

// Merge met Keep Non-Matches om discrepanties te vinden
Mode: Combine
Output: Keep Non-Matches
Result: Items met voorraadverschillen

3. Multi-Channel Price Comparison

// Vergelijk prijzen across channels
SQL Query:
SELECT 
  sku,
  webshop.price as web_price,
  amazon.price as amazon_price,
  bol.price as bol_price,
  CASE 
    WHEN webshop.price < amazon.price THEN 'Web Cheaper'
    WHEN amazon.price < webshop.price THEN 'Amazon Cheaper'
    ELSE 'Same Price'
  END as price_comparison
FROM input1 webshop
JOIN input2 amazon ON webshop.sku = amazon.sku
JOIN input3 bol ON webshop.sku = bol.sku;

4. Data Deduplication

// Vind en merge duplicates
Workflow:
1. Original dataset
2. Same dataset (copy)
3. Merge met Keep Non-Matches
4. Identify unique records

// Of gebruik SQL:
SELECT DISTINCT * FROM input1
ORDER BY created_date DESC;

Troubleshooting & Common Issues

Issue 1: Merge Node Wacht Niet op Alle Inputs

Probleem: Node executeert voordat alle inputs klaar zijn

Oplossing:

  • Check workflow execution order (v0 vs v1)
  • Gebruik 'Always Output Data' setting
  • Verifieer dat alle input branches data produceren

Issue 2: Unexpected Output Count

Probleem: Meer/minder items dan verwacht

Oplossing:

// Debug je merge logic:
console.log('Input 1 count:', input1.length);
console.log('Input 2 count:', input2.length);
console.log('Expected output:', calculateExpected());

// Check voor:
- Multiple matches setting
- Include unpaired items setting
- Fuzzy compare creating unexpected matches

Issue 3: Field Name Conflicts

Probleem: Overlappende field names overschrijven data

Oplossing:

  • Use 'Always Add Input Number' clash handling
  • Rename fields voor merge
  • Gebruik SQL mode voor precise control

Issue 4: Performance Issues

Probleem: Merge is traag bij grote datasets

Oplossing:

  • Pre-sort data op match fields
  • Gebruik SQL mode met indexes
  • Split data in batches
  • Remove onnodige fields voor merge

Advanced SQL Patterns

-- Pattern 1: Conditional merging
SELECT 
  CASE 
    WHEN i1.priority = 'high' THEN i1.*
    ELSE i2.*
  END as merged_data
FROM input1 i1
FULL OUTER JOIN input2 i2 ON i1.id = i2.id;

-- Pattern 2: Weighted averages
SELECT 
  product_id,
  SUM(rating * weight) / SUM(weight) as weighted_avg_rating
FROM (
  SELECT *, 1.5 as weight FROM input1  -- Recent reviews
  UNION ALL
  SELECT *, 1.0 as weight FROM input2  -- Older reviews
) combined
GROUP BY product_id;

-- Pattern 3: Time-based merging
SELECT 
  i1.*,
  i2.update_data
FROM input1 i1
LEFT JOIN input2 i2 ON 
  i1.id = i2.id AND 
  i2.timestamp = (
    SELECT MAX(timestamp) 
    FROM input2 
    WHERE id = i1.id
  );

-- Pattern 4: Hierarchical merging
WITH RECURSIVE hierarchy AS (
  SELECT * FROM input1 WHERE parent_id IS NULL
  UNION ALL
  SELECT i2.* 
  FROM input2 i2
  JOIN hierarchy h ON i2.parent_id = h.id
)
SELECT * FROM hierarchy;

Merge vs Alternative Approaches

MethodUse CaseProsCons
Merge NodeStandard data combiningVisual, flexible, no codeLimited to input count
Code NodeComplex transformationsFull control, any logicRequires coding
Compare DatasetsDiff and syncBuilt for comparisonLimited merge options
Database QueryDatabase-level joinsBest performanceData must be in DB

Best Practices Checklist

  • ☑️ Understand je data structure voor merge
  • ☑️ Kies de juiste merge mode voor je use case
  • ☑️ Test met kleine datasets eerst
  • ☑️ Handle field name conflicts proactief
  • ☑️ Optimaliseer voor performance bij grote sets
  • ☑️ Documenteer je merge logic
  • ☑️ Implementeer error handling
  • ☑️ Monitor output counts
  • ☑️ Use SQL mode voor complexe requirements
  • ☑️ Consider alternatives voor edge cases

Conclusie

De Merge node is de backbone van data integratie in N8N. Of je nu simpele lijsten combineert of complexe SQL joins uitvoert tussen meerdere bronnen, deze node heeft de flexibiliteit die je nodig hebt.

Met de nieuwe multi-input support en SQL capabilities is de Merge node geëvolueerd van een simpele combine tool naar een volwaardige data integration powerhouse. Master deze node, en je kunt vrijwel elke data challenge aan.

💡 Pro Tip: Begin met de Combine mode voor de meeste use cases. Als je meer controle nodig hebt, upgrade naar SQL mode. Gebruik Append alleen voor simpele concatenaties, en onthoud: Input 1 heeft altijd voorrang bij conflicts!

#n8n #merge node #data integration #sql #join #combine #append #workflow #automation #tutorial