Módulo 1: Google Sheets

Mapeo de Datos

Descripción de la cápsula

Ya dominas las tres operaciones de Google Sheets: leer, append, update. Pero en todas ellas apareció el mismo paso, y siempre lo pasamos rápido: el mapeo. Decir "la columna email de la hoja recibe el valor {{ $json.emailAddress }} del workflow". Esa cápsula es sobre ese paso, porque es donde más se rompen los workflows reales.

El problema es simple de enunciar: la estructura de tus datos casi nunca coincide con la estructura de tu hoja. El formulario manda emailAddress, la hoja tiene email. La API devuelve firstName, la hoja tiene name. El webhook manda la fecha como 1715692800, la hoja la quiere como 2026-05-14. Mapear es traducir entre esos dos mundos.

Dominar el mapeo es lo que separa "el workflow funcionó en mi prueba" de "el workflow funciona con datos reales".


Lo que vas a aprender

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

  • Distinguir entre mapeo automático y manual, y cuándo usar cada uno
  • Mapear campos cuando los nombres no coinciden
  • Transformar valores durante el mapeo (formato, mayúsculas, cálculos)
  • Combinar varios campos en una sola columna
  • Manejar campos faltantes sin que el workflow se rompa
  • Diagnosticar por qué una columna sale vacía o con el dato equivocado

El modelo mental: dos estructuras que hay que casar

Imagina dos listas:

Lo que llega (output del nodo anterior): emailAddress, firstName, lastName, tel Lo que la hoja espera (encabezados): email, name, last_name, phone

El mapeo es trazar las líneas entre las dos listas. Ninguna línea se traza sola si los nombres no son idénticos. Tu trabajo es decirle a n8n: "emailAddress va a email", "firstName va a name", etc.

Si los nombres fueran idénticos en ambos lados, el mapeo automático las traza solo. Como casi nunca lo son, casi siempre haces mapeo manual.


Mapeo automático vs manual

El nodo Google Sheets (en Append y Update) ofrece dos modos en el campo Mapping Column Mode (o similar):

Map Automatically

n8n conecta cada campo del input con la columna de nombre idéntico.

  • ✅ Rápido cuando los nombres ya coinciden perfectamente
  • ❌ Las columnas sin match quedan vacías, sin avisarte
  • ❌ Si el input trae un campo extra, puede intentar crear una columna

Úsalo cuando: controlas el nodo anterior y nombraste los campos exactamente como los encabezados de la hoja.

Map Each Column Manually

Tú defines, columna por columna, qué valor recibe.

  • ✅ Control total — ves exactamente qué va a dónde
  • ✅ Puedes transformar valores en el camino
  • ✅ Las columnas que no mapeas, no se tocan (clave para Update)
  • ❌ Más clics

Úsalo cuando: los nombres no coinciden, necesitas transformar datos, o estás haciendo Update y quieres tocar solo algunas columnas.

Recomendación para este módulo y para producción: usa manual por defecto. El automático es cómodo hasta que un cambio de nombre silencioso te vacía una columna en producción. El manual es explícito: lo que ves es lo que pasa.


Mapear cuando los nombres no coinciden

El caso más común. En modo manual, para cada columna de la hoja eliges su valor con una expression:

Columna de la hojaExpressionEl campo de origen se llamaba
email{{ $json.emailAddress }}emailAddress
name{{ $json.firstName }}firstName
last_name{{ $json.lastName }}lastName
phone{{ $json.tel }}tel

La columna de la hoja manda; tú buscas en el input de dónde sacar su valor.


Transformar valores durante el mapeo

El mapeo no solo copia — puede transformar. La expression puede incluir lógica:

Normalizar texto

{{ $json.email.toLowerCase().trim() }}

Email en minúsculas y sin espacios — clave para que los lookups de la cápsula 03 funcionen.

Formatear fechas

{{ $now.toFormat('yyyy-LL-dd') }}

Fecha actual como 2026-05-14 en vez del objeto completo.

Valor por defecto si falta

{{ $json.city || 'Sin especificar' }}

Si city no llega, escribe "Sin especificar" en vez de dejar la celda vacía.

Combinar campos

{{ $json.firstName }} {{ $json.lastName }}

Une nombre y apellido en una sola columna full_name.

Calcular

{{ $json.price * $json.quantity }}

Escribe el total en una columna calculada.

Estas transformaciones son expressions — el tema de G1-M06 y que G4 (Data Handling) profundiza mucho más. Aquí solo necesitas saber que el mapeo es un buen lugar para aplicarlas: limpiar y formatear justo antes de escribir.


Manejar campos faltantes

El error más común en producción: el input a veces trae un campo y a veces no. El formulario tiene un campo opcional, la API a veces omite un dato.

El síntoma

{{ $json.phone }} cuando phone no existe → la celda queda vacía, o peor, escribe undefined como texto.

La solución: valor por defecto

{{ $json.phone || '' }}

o

{{ $json.phone ?? 'N/D' }}

El || (o ??) dice: "usa esto, pero si no existe, usa lo de la derecha". Esto hace tu mapeo defensivo — funciona aunque el input venga incompleto.

Regla práctica: si un campo del input es opcional, su mapeo siempre debe tener un valor por defecto. No confíes en que "siempre va a venir".


Diagnosticar mapeos rotos

Cuando una columna sale mal, el problema casi siempre es uno de estos tres:

SíntomaCausa probableRevisa
Columna vacíaEl nombre del campo no coincide / el campo no existe en el inputEl nombre exacto del campo en el output del nodo anterior
Columna con undefined o [object Object]Estás mapeando un campo que no existe o un objeto completoQue la expression apunte a un valor, no a un objeto
Columna con el dato equivocadoMapeaste el campo de origen incorrectoQue $json.X sea realmente la X que crees

La herramienta de diagnóstico #1: ejecuta el nodo anterior al de Google Sheets y mira su output real. No adivines cómo se llaman los campos — míralos. Lo que ves en ese output es exactamente lo que puedes mapear.


Trampas comunes

Trampa 1: Confiar en el mapeo automático con nombres "casi" iguales

Qué pasa: El input tiene Email (con mayúscula) y la hoja email. El automático no los conecta — para él son nombres distintos — y la columna queda vacía.

Cómo evitar: Mapeo manual, o asegúrate de que los nombres sean idénticos (mayúsculas incluidas).


Trampa 2: Mapear un objeto completo en vez de un valor

Qué pasa: El input tiene { "customer": { "name": "Ana" } } y mapeas {{ $json.customer }}. La celda muestra [object Object].

Cómo evitar: Baja hasta el valor real: {{ $json.customer.name }}.


Trampa 3: No poner valor por defecto en campos opcionales

Qué pasa: El campo company es opcional. Cuando no viene, la celda muestra undefined literalmente.

Cómo evitar: {{ $json.company || '' }} en todo campo que pueda faltar.


Trampa 4: Cambiar los encabezados de la hoja y romper todo

Qué pasa: Renombras la columna email a contact_email en la hoja. Todos los mapeos que apuntaban a email ahora apuntan a una columna que no existe.

Cómo evitar: Los encabezados de la hoja son un contrato. Si los cambias, revisa todos los workflows que escriben en esa hoja. Mejor: no los cambies.


Trampa 5: Mapear sin haber visto el output real del nodo anterior

Qué pasa: Asumes que el webhook manda name pero en realidad manda fullName. Todo el mapeo está adivinado y la mitad sale vacío.

Cómo evitar: Siempre ejecuta el nodo anterior y mira su output antes de mapear. Es 30 segundos que te ahorran media hora de debugging.


Ejercicio: mapear datos "sucios"

Objetivo: practicar el mapeo manual con datos que no coinciden con la hoja.

Preparación

Hoja Contactos con columnas: email, full_name, city, signup_date

El input "sucio"

Usa un nodo Set que produzca esto (datos que NO coinciden con la hoja):

{
  "Email": "ANA@EXAMPLE.COM ",
  "firstName": "Ana",
  "lastName": "López"
}

Nota: Email con mayúscula y espacios, no hay city, no hay date, el nombre viene partido.

Tu tarea

Configura un Google Sheets Append, mapeo manual, que produzca una fila limpia:

  • email → email en minúsculas y sin espacios
  • full_name → nombre y apellido unidos
  • city → "Sin especificar" (no viene en el input)
  • signup_date → la fecha de hoy formateada
Ver soluciones
  • email{{ $json.Email.toLowerCase().trim() }}
  • full_name{{ $json.firstName }} {{ $json.lastName }}
  • city{{ $json.city || 'Sin especificar' }}
  • signup_date{{ $now.toFormat('yyyy-LL-dd') }}

Resultado en la hoja: ana@example.com | Ana López | Sin especificar | 2026-05-14


Resumen y siguiente paso

  • El mapeo es traducir entre la estructura de tus datos y la estructura de la hoja — casi nunca coinciden
  • Mapeo automático: rápido pero conecta solo nombres idénticos y falla en silencio. Manual: explícito y con control total
  • Para producción, usa manual por defecto
  • El mapeo puede transformar: normalizar texto, formatear fechas, combinar campos, calcular, poner valores por defecto
  • Todo campo opcional necesita un valor por defecto ({{ $json.x || '' }}) — mapeo defensivo
  • Para diagnosticar: ejecuta el nodo anterior y mira su output real — no adivines los nombres
  • 5 trampas: confiar en automático con nombres "casi" iguales, mapear objetos, faltar valores por defecto, renombrar encabezados, mapear sin ver el input

Antes de avanzar deberías poder:

  • Hacer mapeo manual cuando los nombres no coinciden
  • Transformar un valor durante el mapeo
  • Poner valores por defecto en campos opcionales
  • Diagnosticar una columna que sale vacía

Lo que sigue (cápsula 07):

Ya sabes leer, escribir, actualizar y mapear. Pero en producción aparecen problemas que no son de lógica sino de la API de Google: rate limits, formatos de fecha que se rompen, números que se vuelven texto, permisos que caducan. La cápsula 07 es el manual de troubleshooting de Google Sheets.


Recursos adicionales

  1. n8n Expressions Docs - Sintaxis completa de expressions para transformar valores.
  2. n8n Data Mapping Docs - Cómo n8n maneja el mapeo entre nodos.
  3. Luxon (formateo de fechas) - La librería de fechas que usa n8n; tokens de toFormat().

Creado: Mayo 14, 2026 Versión: 1.0