Módulo 4: Merge Avanzado y Fan-Out / Fan-In

Patrón: Combinar Fuentes con Combine

Descripción de la cápsula

El caso más útil de Merge en práctica: tienes datos en 2 fuentes (Sheet + CRM, API A + API B, DB + spreadsheet) y necesitas unirlos por un campo común. Equivale a un SQL JOIN, pero visualmente con nodos.

En esta cápsula vas a profundizar Combine en escenarios reales, los patrones para preparar datos antes del Combine, cómo manejar claves de match heterogéneas (un sistema usa email, otro user_id), y los workflows completos donde Combine es la pieza central.


Lo que vas a aprender

  • Aplicar Combine en casos de negocio reales
  • Preparar datos antes del Combine para matches limpios
  • Manejar keys distintas entre fuentes
  • Detectar inconsistencias entre fuentes con Keep Non-Matches

El caso clásico: enrichment

Caso: Sheet con leads básicos (nombre, email). CRM con datos extra (fuente, score, último contacto). Quieres combinarlos.

Workflow

[Schedule diario]
   │
   ├─→ [Sheet: leer leads]      ← Input 1: básicos
   │
   └─→ [HTTP: CRM API leads]    ← Input 2: con datos extra
   │
   ▼
[Merge: Combine Enrich Input 1 by email]
   │
[Procesar leads enriquecidos]

Output: todos los leads del Sheet, enriquecidos con datos del CRM cuando hay match.


Preparar datos antes del Combine

Combine matchea exactamente. Diferencias sutiles rompen matches. Patterns para preparar:

Pattern 1: Normalizar formato del key

[Sheet read]
   │
[Set: normalizar email]
  email_normalized: {{ $json.email.toLowerCase().trim() }}

Hacer lo mismo en Input 2. Combine ahora matchea email_normalized.

Pattern 2: Convertir tipos

[API read]
   │
[Set: convertir id]
  id_str: {{ String($json.id) }}

Si Sheet tiene id como string y API como number, normalizar a uno.

Pattern 3: Resolver claves diferentes

Sheet usa email. API usa user_email. Mapear en el Combine:

  • Input 1 Field: email
  • Input 2 Field: user_email

n8n compara los valores, aunque los nombres sean distintos.


Caso: detectar leads "huérfanos"

Caso: quieres encontrar leads que están en tu CRM pero no en el Sheet activo (probablemente dormidos, candidatos a reactivar).

[Sheet read activos]
   │
   ├──┐
   │  │
[API CRM read todos]
   │  │
   ▼
[Merge: Combine Keep Non-Matches by email — solo los del Input 2 que no están en Input 1]
   │
[Slack: "Lista de leads dormidos: ..."]

Output: leads en CRM no en Sheet activo → candidatos a campaña de reactivación.


Caso: validar consistencia entre sistemas

Caso: Sheet de inventory y API de Shopify deberían tener mismos productos. Detectar discrepancias.

[Sheet: productos en sheet]
   │
   ├──┐
   │  │
[Shopify API: productos]
   │  │
   ▼
[Merge: Combine Keep Non-Matches by sku]
   │
[Sheets: append "discrepancies.csv"]
   │
[Slack: "Detectadas N discrepancias"]

Cada vez que corre, te reporta items que no matchean.


Caso: pricing dinámico con tabla externa

Caso: Webhook con pedido. Necesitas pricing actualizado desde Sheet de pricing dinámico.

[Webhook: pedido con product_id]
   │
   ├──┐
   │  │
[Sheet read: pricing.csv]
   │  │
   ▼
[Merge: Combine Enrich Input 1 by product_id]
   │
[Output: pedido + price actualizado]

Cada pedido se enriquece con el price actual del Sheet. Útil para reglas de pricing que cambian seguido.


Caso: agregar contexto desde múltiples fuentes

Pattern de 3+ fuentes:

[Webhook: lead]
   │
   ├──[Combine 1: Lead + Clearbit data]
   │     │
   │     ├──[Combine 2: + datos de redes sociales]
   │     │     │
   │     │     ├──[Combine 3: + score interno]
   │     │     ▼
   │     │   [Resultado: lead super enriquecido]

Cascada de Combines, cada uno agregando una fuente.


Trampas comunes

Trampa 1: Whitespace en keys

Qué pasa: Sheet tiene email: "mike@nieva.team " (espacio al final). API tiene email: "mike@nieva.team". Combine no matchea.

Cómo evitar: Trim keys siempre antes de Combine.


Trampa 2: Capitalization

Qué pasa: Mike@nieva.team vs mike@nieva.team. No matchea.

Cómo evitar: toLowerCase todos los emails antes de Combine.


Trampa 3: Keys con tipos distintos

Qué pasa: Number vs string. 1 vs "1". No matchea.

Cómo evitar: Convertir explícitamente: String(id) o Number(id).


Trampa 4: Multiple matches in Input 2

Qué pasa: Input 1 tiene 1 lead con email X. Input 2 tiene 3 records con email X (duplicados). Output depende del modo — puede tener 3 items para ese lead o solo el primero.

Cómo evitar:

  • Dedupar Input 2 antes del Combine
  • O entender qué comportamiento esperas y validarlo con test

Trampa 5: Combine con datasets enormes

Qué pasa: Combine de 10,000 items × 10,000 items. n8n carga ambos en memoria.

Cómo evitar:

  • Para volúmenes grandes, considera procesar en batches (SplitInBatches de Input 1, lookup en Input 2 por batch)
  • O usar DB con JOIN nativo si es muy grande

Ejercicio: workflow Combine real

Objetivo: practicar con datos reales.

Tu tarea

  1. Sheet A: leads_basic con columnas email, name, source. Llena con 10 leads.

  2. Sheet B: leads_scores con columnas email, score, last_activity. Llena con 7 emails (5 que matchean Sheet A, 2 que no).

  3. Workflow:

    • Manual Trigger
    • Sheet A read (Input 1)
    • Sheet B read (Input 2)
    • Combine Enrich Input 1 by email
    • Slack: mensaje con cada lead + score (o "sin score" si no matchea)
  4. Pruebas:

    • Cambia uno de los emails a MAYÚSCULA. Verifica que no matchea.
    • Agrega Set para normalizar (lowercase) antes del Combine. Verifica que ahora sí matchea.

Resumen y siguiente paso

  • Combine es el patrón más útil de Merge en práctica
  • Preparar datos antes (normalizar, convertir tipos)
  • 3 casos comunes: enrichment, detectar huérfanos, validar consistencia
  • Cascada de Combines para multi-source
  • 5 trampas: whitespace, capitalization, tipos, multi-match, datasets enormes

Lo que sigue: Paralelismo con sincronización — el patrón Wait para esperar a múltiples ramas.


Creado: Mayo 11, 2026 Versión: 1.0