Primer flujo de trabajo: activación manual → editar campos → código

Lo de las cotizaciones lo calculé a mano en una hoja de cálculo durante dos años: cantidad por precio unitario, más el flete, y luego dividir para sacar el costo unitario. Doscientas bolsas, precio unitario de un yuan con ochenta y cinco, flete de sesenta, el conjunto sale cuatrocientos treinta yuanes, dos yuanes con quince por unidad. Los números no son complicados, el problema es que olvidé el flete dos veces, y la cotización ya se había enviado al cliente.

Después trasladé este cálculo a n8n, tres nodos, cambio un número y lo ejecuto de nuevo, en dos segundos sale el nuevo precio. Este artículo trata de esas tres etapas desde el lienzo en blanco hasta que funciona, incluido el error de la primera vez que calculé 430 como 37060.

Solo hay dos requisitos previos: n8n ya está instalado y se puede abrir (si no lo has instalado, consulta《Cómo instalar n8n》), y estar familiarizado con el lienzo, el panel de nodos y el historial de ejecuciones (si no, revisa《Guía de la interfaz》). No hace falta saber programar, el bloque de código se copia tal cual.

Tres nodos, cada uno se encarga de una cosa

El error más común de los principiantes es tratar los tres nodos como «tres pasos». No son pasos, son tres roles.

  • Manual Trigger (disparador manual): genera un dato vacío y lo envía hacia abajo. No consulta la base de datos, no recibe peticiones, no mira la hora, es puramente «lo pulsas una vez y se ejecuta una vez». El primer workflow lo usa para reducir las variables a una: de dónde vienen los datos es algo que por ahora no hay que preocuparse.
  • Edit Fields (editar campos): inserta campos en el item, o modifica los existentes. El número de items no cambia, entra uno y sale uno. En tutoriales antiguos se llama Set, hace tiempo que se renombró, el panel de nodos de 2.43.7 muestra Edit Fields (Set), ambos nombres se pueden buscar.
  • Code (código): el único paso que puede cambiar el número de items. Uno se puede dividir en varios, varios se pueden comprimir en uno. Por eso su valor de retorno debe ser un array: esta es su mayor diferencia con los demás nodos, y también donde más errores se producen.

Mi instancia es 2.43.7, con la interfaz cambiada a chino simplificado. Una advertencia: la interfaz en chino solo tradujo el texto descriptivo y los botones, los nombres de nodos y de parámetros siguen en inglés. Si buscas «编辑字段» no encuentras nada, tienes que buscar edit fields. Esos tutoriales de internet que escriben «nodo Set» o «Keep Only Set Fields del nodo Set» tampoco coinciden con la interfaz de 2.x, no dudes de ti mismo.

Qué es exactamente lo que se transmite entre nodos

Sin aclarar esto, cada error posterior solo se puede adivinar.

En n8n, todos los datos que fluyen entre nodos son un array, y cada elemento del array tiene esta forma:

[
  { "json": { "qty": 200 } },
  { "json": { "qty": 150 } }
]

El corchete exterior es "un lote"; dentro, cada objeto es un dato, y n8n lo llama item. Los campos reales del negocio van metidos en json esta clave. Así que "procesar 200 pedidos" en este modelo no es iterar 200 veces, sino entregar de una vez 200 items al nodo, y el nodo los procesa uno por uno.

Este diseño trae dos consecuencias. La buena noticia es que el nodo trabaja en lote de forma natural, no hace falta escribir bucles. La mala noticia es que, al escribir código, lo que tienes en mano es un array, no un objeto individual—row.qty esta forma de escribirlo no se puede aplicar directamente sobre un array, primero hay que extraer el primer elemento.

De un lienzo vacío a tres nodos

  1. En la esquina superior derecha de la lista de workflows, "New workflow", o escribir directamente en la barra de direcciones /workflow/new. Yo prefiero lo segundo, es más rápido.
  2. En el lienzo vacío, haz clic en el botón de la esquina superior derecha +(también puedes hacer clic en el signo más del centro del lienzo), y el panel muestra "What happens next?".
  3. En el cuadro de búsqueda escribe manual trigger, selecciona Manual Trigger.
  4. Pasa el ratón sobre el pequeño círculo a la derecha del nodo, aparece un +, haz clic en él, busca edit fields, selecciona Edit Fields (Set). Añade de esta forma, las conexiones se conectarán solas, sin necesidad de arrastrar manualmente.
  5. Repite de nuevo, busca code, selecciona Code.
  6. El nombre del nodo es en inglés por defecto. Haz doble clic en el título para cambiarlo, yo lo cambié a chino: activación manual, rellenar cotización, calcular importe. Cuando hay muchos nodos, al echar un vistazo a los nombres en inglés todo son Trigger, Set, Code, cambiar a chino es puramente para descansar la vista, funcionalmente no tiene ningún impacto.
n8n 添加节点面板里搜索 edit fields,结果为 Edit Fields (Set) 节点
Busca edit fields y solo aparece un resultado. La línea de texto pequeño debajo Modify, add, or remove item fields aclara su función: solo modifica campos, no crea datos.

Editar campos: añadir cuatro campos a un dato

Haz doble clic en «rellenar cotización» para abrir el panel, solo hay dos parámetros que modificar.

Mode Mantener Manual Mapping, que es la forma de rellenar formulario. La otra opción JSON Output es escribir directamente un fragmento de JSON, más cómodo para hacer estructuras anidadas, en la etapa inicial no lo uses por ahora.

Fields to Set añade cuatro filas. En cada fila, a la izquierda está el nombre del campo, en el medio el desplegable de tipo, a la derecha el valor:

Nombre del campo Tipo 值
product cadena bolsa de compresión al vacío 60x80cm
qty número 200
unit_price número 1.85
freight número 60

El desplegable de tipo por defecto es «cadena»; qty, unit_price y freight deben cambiarse manualmente a «número». La interfaz no te lo impide, y si eliges mal tampoco da error: guarda 200 como "200" sin avisar. Lo doloroso de esta trampa lo verás cuando hagamos el cálculo.

n8n 编辑字段节点参数:Mode 为 Manual Mapping,四个字段 product、qty、unit_price、freight
Cuatro campos, tres son números. Los nombres de campo usan guion bajo en lugar de camelCase porque luego hay que concatenarlos al escribir el código row.unit_price, y si falta un carácter se convierte en undefined.

El interruptor de la parte inferior del panel Include Other Input Fields está activado por defecto, lo que significa «los campos de la entrada que no he tocado se emiten tal cual». La entrada de este flujo está vacía, así que da igual que esté activado o desactivado. Pero en un flujo con datos, desactivarlo equivale a eliminar todos los campos de origen y dejar solo los cuatro que rellenas a mano; entonces, si el código no encuentra product, no pienses que el código está mal.

Nodo de código: toma un elemento, calcula una vez, devuelve un elemento

Haz doble clic en «Calcular importe».Mode Mantener Run Once for All Items(recorrer todo el array una vez),Language Mantener JavaScript. Luego pega el siguiente bloque en el área de edición:

const row = items[0].json;
const amount = row.qty * row.unit_price + row.freight;
const unitCost = Number((amount / row.qty).toFixed(2));

return [{
  json: {
    product: row.product,
    qty: row.qty,
    amount,
    unitCost,
    summary: row.product + ' ' + row.qty + ' 个,含运费合计 ' + amount + ' 元,单个成本 ' + unitCost + ' 元',
  },
}];

Línea por línea, solo lo que puede morder.

items[0].json Toma el primer elemento. Aquí solo hay un dato, así que basta con [0]. En escenarios con múltiples elementos hay que escribir items.map(...), eso es tema del siguiente artículo.items es la forma antigua, todavía funciona en 2.x; la forma nueva es $input.first().json, ambas producen exactamente el mismo resultado en esta instancia. Conservo itemsporque en el modo «Run Once for All Items» lo que tienes en mano es precisamente todo el array, y ese nombre es más honesto.

toFixed(2) No es por estética. 430 dividido entre 200 da exactamente 2.15, se ve limpio; si cambias a envío 55, da 2.175, y el cálculo en coma flotante puede dar 2.1749999999999998. Al escribirlo en una tabla o enviarlo a un cliente, esa cola queda fea. La capa exterior Number() Es convertirlo de string a número—toFixed Lo que devuelve es un string; si no se convierte, unitCost quedará alineado a la izquierda en la tabla.

El fragmento del final return es lo importante.Devuelve un array, cada elemento envuelto en una capa de json. n8n usa esta clave json para distinguir «esto son datos de negocio» y «esto es un adjunto binario». Si el formato no es correcto, el nodo se pone en rojo directamente.

n8n 代码节点参数:Mode 为 Run Once for All Items,Language 为 JavaScript
El desplegable Mode tiene dos opciones; si eliges la incorrecta, el código queda completamente inservible. La diferencia está explicada en el punto 2 de «cinco errores que realmente te encontrarás» más adelante.

Ejecútalo una vez y mira la salida

Haz clic en el botón naranja «Ejecutar» debajo del lienzo. En uno o dos segundos, los bordes de los tres nodos se ponen verdes, aparece una pequeña marca de verificación en la esquina superior derecha de cada nodo y en medio de las conexiones se indica «1 elemento».

n8n 三节点工作流执行完成,连线上标注 1 个项目,节点带绿色勾
El «1 elemento» sobre la conexión es cuántos datos han pasado por esa línea. Cuando más adelante añadas nodos de división, aquí aparecerá 3, 5, 10, y de un vistazo podrás ver en qué paso se amplificaron los datos.

Haz doble clic en «Calcular importe» y cambia el área de salida de la derecha a la pestaña JSON:

n8n 代码节点输出的 JSON:amount 430、unitCost 2.15 与拼好的 summary
430 es 200×1.85+60, 2.15 es 430÷200. Si lo calculas a mano y coincide, significa que los tres nodos están bien conectados.

Por cierto, algo que se malinterpreta fácilmente: este botón «Ejecutar» solo se ejecuta cuando tú haces clic. Un workflow con Manual Trigger no se pone en marcha solo porque se publique; no tiene mecanismo para «activarse solo». Para programarlo, hay que cambiar a un trigger del tipo Schedule Trigger.

Adjunto: el JSON completo del workflow

Si no quieres ir haciendo clic en los nodos, puedes importarlo entero. Copia el siguiente fragmento y pulsa en un espacio vacío del lienzo Ctrl+V, los tres nodos caen directamente sobre el lienzo. También vale ir por el menú: esquina superior derecha ⋯ → Importar → Importar desde archivo, primero guarda el contenido como .json。

Esto lo pegué yo mismo en un flujo de trabajo en blanco y lo ejecuté una vez: tres nodos, dos conexiones, posiciones correctas, y al terminar amount también es 430.

{
  "name": "第一个工作流",
  "nodes": [
    {"parameters":{},"id":"m1","name":"手动触发","type":"n8n-nodes-base.manualTrigger","typeVersion":1,"position":[-368,0]},
    {"parameters":{"assignments":{"assignments":[
      {"id":"a1","name":"product","value":"真空压缩袋 60x80cm","type":"string"},
      {"id":"a2","name":"qty","value":200,"type":"number"},
      {"id":"a3","name":"unit_price","value":1.85,"type":"number"},
      {"id":"a4","name":"freight","value":60,"type":"number"}
    ]},"includeOtherFields":true,"options":{}},"id":"m2","name":"填写报价单","type":"n8n-nodes-base.set","typeVersion":3.5,"position":[-144,0]},
    {"parameters":{"jsCode":"const row = items[0].json;nconst amount = row.qty * row.unit_price + row.freight;nconst unitCost = Number((amount / row.qty).toFixed(2));nnreturn [{n  json: {n    product: row.product,n    qty: row.qty,n    amount,n    unitCost,n    summary: row.product + ' ' + row.qty + ' 个,含运费合计 ' + amount + ' 元,单个成本 ' + unitCost + ' 元',n  },n}];","mode":"runOnceForAllItems"},"id":"m3","name":"计算金额","type":"n8n-nodes-base.code","typeVersion":2,"position":[80,0]}
  ],
  "connections": {
    "手动触发": {"main": [[{"node": "填写报价单", "type": "main", "index": 0}]]},
    "填写报价单": {"main": [[{"node": "计算金额", "type": "main", "index": 0}]]}
  },
  "settings": {"executionOrder": "v1"}
}

Cómo saber si realmente funciona

Cuatro puntos, todos verificables por uno mismo; si falta uno, no cuenta como completado.

  1. Los tres nodos con marco verde y marca de verificación, y ambas conexiones etiquetadas con «1 elemento». Si el número no es 1, significa que algún nodo intermedio cambió la cantidad; hay que revisarlo.
  2. En la salida JSON del nodo de código, amount es 430 y unitCost es 2.15.
  3. En el historial de ejecuciones se puede encontrar esta vez. Las ejecuciones manuales también dejan registro; no pienses que solo las tareas programadas entran en la lista.
  4. Cambia freight de 60 a 100 y vuelve a ejecutar; amount debería pasar a 470. Cambiar una entrada y ver que la salida cambia es más contundente que los tres puntos anteriores: ver solo una vez 430 podría ser coincidencia.

El cuarto punto recomiendo hacerlo siempre. Que funcione una vez y que funcione correctamente están separados por una capa.

Cinco errores que realmente te vas a encontrar

1. Code doesn't return items properly

Devolvió una cadena. En mi prueba solo escribí una línea return "共 430 元";, el nodo se vuelve rojo de inmediato y aparece este mensaje en la esquina inferior derecha.

n8n 代码节点返回字符串时报错:Code doesn't return items properly
Recuadro rojo, signo de exclamación blanco, un mensaje de error en inglés. Los dos nodos anteriores siguen en verde, lo que indica que el error está en el último.

Lo interesante es que,return { amount: 430 } esta forma de escribir sin envolver en un array ni en jsonfunciona.. El nodo Code te añade automáticamente la clave json y los corchetes; la documentación especifica este comportamiento. Así que este error no es «el formato no es lo suficientemente estándar», sino «lo que devuelves no es un dato en absoluto»: las cadenas, los números y null no se pueden completar.

2. items is not defined [line 1]

El Mode se seleccionó como Run Once for Each Item, y en el código se sigue usando items. En el modo por elemento, n8n solo introduce un elemento a la vez, y el actual se llama $json; para obtener la cantidad hay que escribir $json.qty. La diferencia entre los dos modos se resume en una frase: ejecutar todo el array una vez, o ejecutar cada elemento una vez. Antes de escribir código, mira primero este desplegable.

3. Solo se permite un nodo "Manual Trigger" en un workflow

Añadir otro trigger a un workflow que ya tiene uno. Esta vez cometí un error aún más tonto: pegué un JSON con trigger en el lienzo de un workflow existente, apareció «No se puede insertar el nodo» y debajo este mensaje. Para probar comparando, abre primero un workflow nuevo y luego pega.

4. La salida muestra undefined y no da error

En Edit Fields el campo se llama unit_price, y en el código se escribe como row.unitPrice. Una diferencia de un carácter entre mayúsculas/minúsculas y guion bajo, a n8n le da igual, a JS también, y el resultado es que undefined se propaga hacia abajo, y en el summary aparece «含运费合计 undefined 元». Este tipo de error es el más difícil de rastrear, porque no se marca en rojo, no suena, solo el número está mal.

5. amount se convierte en "37060"

El tipo de campo se seleccionó como string. Sesenta y "60" en JS parecen iguales, pero + al encontrarse con un string lo convierte en concatenación: 370 más "60" da "37060", no 430.

n8n 编辑字段里 freight 类型选成字符串后,代码输出 amount 变成 37060
En la entrada izquierda, el icono delante de freight pasa de # a T, y a la derecha amount se convierte en "37060" con comillas, y unitCost pasa a 185.3. Todo el flujo no da error, y además afirma con toda tranquilidad «合计 37060 元».

El quinto punto es el más valioso de este artículo. La primera vez que obtuve este número, me quedé mirando 37060 durante medio minuto antes de darme cuenta de que era concatenación de strings; porque el código parecía no tener ningún problema, el problema estaba en el desplegable de tipo del nodo anterior.

Los tres límites del nodo Code

El nodo Code se ejecuta en el propio proceso de n8n, pero con sandbox: no puede leer archivos locales ni enviar peticiones HTTP. Para manipular archivos usa el nodo Read/Write File From Disk, para enviar peticiones usa el nodo HTTP Request. Esto no es una carencia, es reducir al mínimo «cuánto daño puede hacer un fragmento de JS pegado sin pensar».

Pero hay tres cosas que no puede bloquear y que tienes que gestionar tú.

No pegues sin más un JSON de workflow que te haya dado otra persona.Pegarlo equivale a ejecutar en tu propia instancia JS escrito por otro. En mi instancia, pegar JSON coloca los nodos directamente, sin confirmación ni pregunta de origen. Si de verdad quieres probarlo, primero mételo en una instancia de prueba vacía, revisa el código y luego decide si ejecutarlo.

No hardcodees claves en el código.Un workflow se puede exportar completo, enviar a un compañero, pegar en el grupo. La api key escrita directamente en el código se va con el JSON. Hay que ponerla en un nodo de credenciales para que n8n la almacene cifrada.

El autoalojamiento permite instalar paquetes npm de terceros.Por defecto está desactivado, hay que habilitar manualmente la variable de entorno. Activarlo equivale a abrir una vía de ejecución de código arbitrario para el nodo Code. En una instancia de uso personal da igual, en una instancia compartida por varios recomiendo dejarlo siempre desactivado.

Resumen

Tres nodos, una cadena: el trigger genera datos, Edit Fields los completa, el código los calcula. Lo que realmente hay que recordar no es cómo se hace clic en estos tres nodos, sino la forma de «array que contiene json». Después, IF, Merge, bucles y ramas de error son todos variantes de esta forma.

Si se puede evitar el código, mejor. Este presupuesto también se puede calcular con Edit Fields más expresiones,{{ $json.qty * $json.unit_price + $json.freight }} una línea y listo, además un nodo menos. Elegí Code al final porque después hay que calcular presupuestos con tres criterios a la vez, y acumular expresiones en el nodo es más difícil de mantener que escribir código. Si solo calculas un número, no uses código.

Ese problema de tipos, te sugiero que ahora mismo cambies freight a string a propósito y lo ejecutes una vez, para ver con tus propios ojos cómo 430 se convierte en 37060. Leer diez veces el texto no supera equivocarse una vez uno mismo.

Continuar hacia abajo

El artículo anterior es«Cómo elegir entre n8n, Zapier y Make». Cómo se ven los nodos, las conexiones y las ejecuciones en el JSON,este artículoya lo desglosó. Cuando el servicio no arranque o el port choque, consulta«Cómo diagnosticar errores de inicio y ocupación de port en n8n». Para la instalación, consultaeste artículo, si no estás familiarizado con la interfaz, revisaeste artículo. El índice completo del curso está enaquí。

Referencias

  • Manual Trigger: solo se ejecuta cuando haces clic en ejecutar, no proporciona activación automática; solo se permite uno por workflow
  • Edit Fields (Set): dos modos, Manual Mapping y JSON Output, y la función de Include in Output
  • Code: diferencias entre los dos Mode, opciones de lenguaje, no puede acceder al sistema de archivos ni iniciar solicitudes HTTP
  • Understand n8n's data structure: el origen de arrays anidados en json, y la explicación de cómo el nodo Code añade automáticamente la clave json
  • Usa los atajos integrados: variables y métodos integrados en las expresiones, cuáles no son aplicables en el nodo Code

Última actualización: 28 de octubre de 2026, usando n8n 2.43.7.

THE END