Módulo 2: Branching y Decisiones Avanzadas

Filtros en Cadena

Descripción de la cápsula

Cuando un workflow procesa N items (filas de un Sheet, registros de un API, items de un webhook batch), rara vez todos son relevantes. Algunos son inválidos, otros no cumplen criterios de negocio, otros son duplicados. Filtros en cadena es el patrón de aplicar filtros secuenciales que progresivamente reducen el conjunto al subset relevante, antes de hacer operaciones costosas (API calls, emails, etc.).

Sin filtros en cadena: procesas 1000 items, muchos fallan al final, gastas recursos. Con filtros en cadena: filtras 1000 → 200 → 50 → 20, y solo procesas los 20 relevantes con operaciones costosas. Latencia, costos y errores se reducen dramáticamente.


Lo que vas a aprender

Al terminar esta cápsula serás capaz de:

  • Identificar el momento de aplicar cada filtro
  • Diseñar la cadena ordenando filtros del más barato al más costoso
  • Distinguir Filter de IF (uso de cada uno)
  • Combinar filtros declarativos y programáticos
  • Aplicar el patrón a casos de negocio reales

El modelo mental: el embudo

Piensa en un embudo. Los datos llegan por arriba. Cada filtro en cadena es un nivel del embudo que reduce la cantidad de items que pasan al siguiente nivel.

         [1000 items]
         ▼
    [Filter 1: válidos]
         ▼ 850
    [Filter 2: con consentimiento]
         ▼ 600
    [Filter 3: no duplicados]
         ▼ 480
    [Filter 4: en mercado clave]
         ▼ 150
    [Operación costosa: enviar email]
         ▼

Cada filtro es rápido y declarativo — solo dice "este item pasa o no pasa".


Filter node vs IF (revisited)

En G1-M07-02 viste la diferencia. Recapitulamos en contexto de cadena:

Filter

  • 1 entrada, 1 salida (solo los que pasan)
  • Los que no pasan se descartan silenciosamente
  • Ideal para cadena porque cada filter se conecta al siguiente directamente

IF

  • 1 entrada, 2 salidas (TRUE y FALSE)
  • Útil cuando quieres manejar los que no pasan
  • En cadena, los FALSE necesitan ir a algún lado o se descartan implícitamente

Para cadenas, usa Filter salvo que necesites manejar los rechazados.


Orden de filtros: barato primero

El orden importa. Aplicar primero los filtros más baratos (que descartan más sin esfuerzo).

Ejemplo

Procesar leads del Sheet. Filtros disponibles:

  1. Email no vacío (rápido, expression simple)
  2. Email formato válido (rápido, regex)
  3. No es spam dominio (rápido, lookup)
  4. No es duplicado (medio, requiere comparar contra Sheet existente)
  5. Verificado con API externa (lento, llama API por cada item)

Orden correcto:

Sheet → Filter 1 (email) → Filter 2 (formato) → Filter 3 (spam) → Filter 4 (duplicado) → API → ...

Por qué:

  • Filter 1 descarta 30% sin esfuerzo
  • Filter 2 descarta otro 5%
  • Filter 3 descarta otro 10%
  • Filter 4 (más costoso) opera solo sobre los 55% que sobrevivieron
  • API (más cara) solo se llama para los items finales

Si invirtieras el orden, la API se llamaría para los 1000 items, gastando crédito y rate limit en items que iban a descartarse de todas formas.


Patrones de filtros típicos

Patrón 1: Validación básica

[Sheet] → [Filter: email no vacío] → [Filter: nombre no vacío] → ...

Items con datos faltantes se descartan temprano. Evita errores downstream.

Patrón 2: Compliance / legal

[Sheet] → [Filter: marketing_consent = true] → ...

Sin consentimiento, no procesar (GDPR/CAN-SPAM). Filtro absoluto.

Patrón 3: Business rules

[Sheet] → [Filter: monto > threshold] → [Filter: pais en mercados] → ...

Solo lo que cumple criterios de negocio sigue. El resto se descarta.

Patrón 4: Deduplicación

[Sheet] → [Filter: no procesado antes] → ...

Implementación común: comparar contra un Sheet procesados con IDs. Solo los nuevos pasan.

Patrón 5: Time-based

[Sheet] → [Filter: fecha > hace 7 días] → ...

Solo items recientes. Útil en batch jobs que procesan "lo nuevo desde la última vez".


Implementación: filter con expression

El Filter node de n8n usa la misma sintaxis que IF para condiciones:

Filter:
  Conditions: {{ $json.email }} is not empty

O más complejo:

Filter:
  Conditions:
    - {{ $json.email }} is not empty
    - {{ $json.consent }} is true
    Combinator: AND

Como Filter solo tiene "1 salida" (los que pasan), el output del Filter es solo los items que cumplen TODAS las condiciones (si AND) o ALGUNA (si OR).


Implementación: filter con Set + Filter (cuando es complejo)

Si la condición es muy compleja, primero pre-computa un Boolean con Set, después Filter sobre ese Boolean.

[Set: agregar Booleans]
  - passes_basic_validation
  - passes_compliance
  - is_key_market

[Filter: passes_basic_validation is true]
   │
[Filter: passes_compliance is true]
   │
[Filter: is_key_market is true]
   │
[resto del workflow]

Ventaja: cada Filter es muy claro. Si quieres debuggear, inspeccionas el Set y ves exactamente qué Booleans tiene cada item.


Combinar filtros declarativos y programáticos

A veces los filtros se vuelven complejos. Tienes opciones:

Filtros declarativos (Filter node)

  • Para condiciones simples (1-3 reglas)
  • Pros: visual, fácil de mantener
  • Cons: limitado para lógica avanzada

Filtros programáticos (Code node)

  • Para lógica compleja con loops, manipulación
  • Pros: full power de JavaScript
  • Cons: menos visual, requiere conocer JS

Híbrido

Filtros simples = Filter node. Filtros complejos = Code.

[Filter: básicos] → [Filter: compliance] → [Code: lógica de scoring compleja] → [Filter: score > threshold]

Caso completo: procesar leads del día

Requirements

Diariamente, procesar leads del Sheet. Solo enviar email a los que:

  1. Tienen email no vacío y formato válido
  2. Dieron consentimiento de marketing
  3. No están en lista de spam
  4. No los procesamos en últimos 30 días
  5. Son de países de mercado clave
  6. Tienen score > 50 (cálculo complejo)

Workflow

[Schedule diario]
   │
[Sheets: leer todos los leads]
   │
[Filter 1: email no vacío]
   │
[Filter 2: email formato válido — regex]
   │
[Filter 3: dominio no en blacklist]
   │
[Sheets: leer leads procesados últimos 30 días]
   │
[Merge: combine, sub-modo "keep non-matches" — solo los nuevos]
   │
[Filter 4: pais en mercados clave]
   │
[Code: calcular score por lead]
   │
[Filter 5: score > 50]
   │
[Send Email para los que pasaron todos los filtros]

Comentarios

  • Filtros baratos primero (1, 2, 3 son local — solo expressions)
  • Filtros con I/O después (lectura de Sheet de procesados)
  • Cálculo costoso al final (score con Code)
  • Operación final (Send Email) solo se ejecuta para items que pasaron todos los filtros

Si tienes 1000 leads iniciales y el embudo termina en 50, solo 50 emails se envían (vs los 1000 que tendrías sin filtros).


Anti-patrones

Anti-patrón 1: Filtrar después del operación costosa

[Sheet] → [Send Email a todos] → [Filter: consentimiento = true]

Ya enviaste el email. El filter es inútil — el daño está hecho.

Cómo evitar: filtros ANTES de operaciones costosas/destructivas.


Anti-patrón 2: Un solo filter con condición monstruosa

[Filter: condición de 20 líneas con AND/OR anidados]

Funciona pero es imposible de debuggear. Si algo no pasa, no sabes cuál de las 8 condiciones falló.

Cómo evitar: descomponer en varios Filter en cadena. Si quieres un solo, usa Set previo con Booleans intermedios.


Anti-patrón 3: Mismo filtro repetido en varias ramas

Tu workflow se bifurca, y cada rama tiene el mismo filter "email no vacío".

Cómo evitar: filtrar antes de bifurcar. Una vez, no N veces.


Anti-patrón 4: Filter sin documentar el "por qué"

Tu cadena tiene 5 Filters. 3 meses después, otra persona pregunta "¿por qué este filter de 'monto > 1000'? ¿de dónde vino ese 1000?".

Cómo evitar: Sticky Note en el canvas con la razón. O renombrar el Filter a algo descriptivo (Filter: solo VIPs (>$1000)).


Trampas comunes

Trampa 1: Filter que descarta todo silenciosamente

Qué pasa: Configuras Filter con condición que siempre es false por un bug en la expression. Todos los items se descartan. El workflow termina con 0 items procesados, sin error.

Cómo evitar:

  • Verificar count del Filter output durante development
  • Agregar Slack notification "procesados X items hoy" — si siempre es 0, hay bug

Trampa 2: Filter que muestra todos cuando esperabas pocos

Qué pasa: Tu Filter es email is not empty pero estructura es body.email. Filter no encuentra email directo → considera todos los items como "pass" porque undefined is not empty puede comportarse raro.

Cómo evitar: inspeccionar el output del trigger y usar el path completo.


Trampa 3: Filter con tipo equivocado

Qué pasa: Filter amount > 1000. amount viene como string "1500". La comparación "1500" > 1000 puede dar resultados inesperados.

Cómo evitar: Set previo que convierte tipos. O en el Filter, usar Number($json.amount) > 1000.


Trampa 4: Asumir que Filter mantiene orden

Qué pasa: Procesabas items en orden cronológico, esperabas que el Filter mantuviera ese orden. En algunos casos n8n procesa en paralelo y el orden se pierde.

Cómo evitar: Si necesitas orden, explícitamente ordenar después con Sort node o equivalente.


Trampa 5: Filter después de Aggregate

Qué pasa: Tienes Aggregate (combina N items en 1). Después un Filter. El Filter ahora opera sobre 1 item agregado, no sobre los originales.

Cómo evitar: Filter antes de Aggregate si los criterios se aplican a items individuales.


Ejercicio: diseñar embudo

Objetivo: practicar diseño de cadena de filtros.

Tu tarea

Diseña la cadena para este caso:

Tienes un Sheet con suscriptores de newsletter (1000+). Quieres enviar campaña a los que:

  1. Suscritos hace más de 7 días (no spamear nuevos)
  2. No se dieron de baja
  3. Han abierto al menos 1 email en los últimos 90 días
  4. Email no es del dominio competidor.com
  5. País es de un mercado donde la campaña aplica

Diseña la cadena ordenando los filtros del más barato al más costoso.

Solución sugerida
[Sheet: suscriptores]
   │
[Filter 1: no se dio de baja — boolean simple]
   │
[Filter 2: email no termina en @competidor.com — expression]
   │
[Filter 3: pais en mercados — lookup en array]
   │
[Filter 4: suscrito > 7 días — fecha simple]
   │
[Lookup en Sheet de "engagement": leer aperturas últimos 90 días]
   │
[Merge: combine para enriquecer con aperturas]
   │
[Filter 5: aperturas > 0 — el más caro porque requiere lookup]
   │
[Operación: Send Email a los que pasaron]

Orden: el 5 va al final porque requiere I/O. Los 1-4 son expressions locales baratas.


Resumen y siguiente paso

  • Filtros en cadena = embudo que reduce items progresivamente antes de operaciones costosas
  • Orden importa: filtros más baratos primero
  • Filter vs IF: Filter para cadenas, IF cuando necesitas manejar rechazos
  • Patrones típicos: validación, compliance, business rules, dedup, time-based
  • Combinar declarativos (Filter) y programáticos (Code) para casos complejos
  • 4 anti-patrones: filtrar tarde, mega-filter, filter repetido, sin documentar
  • 5 trampas: descartar todo, mantener todo, tipo equivocado, asumir orden, filter después de aggregate

Antes de avanzar deberías poder:

  • Diseñar cadenas de 4-5 filtros con orden correcto
  • Decidir Filter vs IF según caso
  • Combinar filtros declarativos y programáticos cuando aplica

Lo que sigue (cápsula 06):

Ahora vienen los anti-patrones. Específicamente "if hell" — el más común y más doloroso. Vas a aprender a reconocerlo, refactorizarlo, y prevenirlo — y los signos tempranos que indican que tu workflow está yendo en esa dirección.


Recursos adicionales

  1. Filter Node Documentation - Referencia.
  2. Funnel Pattern (Marketing) - Analogía conceptual.
  3. Short-circuit Evaluation - Concepto general aplicado a filtros.

Creado: Mayo 11, 2026 Versión: 1.0