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,telLo que la hoja espera (encabezados):name,last_name,phoneEl 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: "
emailAddressva afirstNameva aname", 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 hoja | Expression | El 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íntoma | Causa probable | Revisa |
|---|---|---|
| Columna vacía | El nombre del campo no coincide / el campo no existe en el input | El 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 completo | Que la expression apunte a un valor, no a un objeto |
| Columna con el dato equivocado | Mapeaste el campo de origen incorrecto | Que $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 espaciosfull_name→ nombre y apellido unidoscity→ "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
- n8n Expressions Docs - Sintaxis completa de expressions para transformar valores.
- n8n Data Mapping Docs - Cómo n8n maneja el mapeo entre nodos.
- Luxon (formateo de fechas) - La librería de fechas que usa n8n; tokens de
toFormat().
Creado: Mayo 14, 2026 Versión: 1.0