Guide

Trasformazione Dati Avanzata con il Nodo Code

Hai già creato qualche flusso, ma ti serve più controllo sulla forma dei dati? Con il nodo code n8n puoi modellare, aggregare e validare i payload in modo preciso, lì dove i nodi no‑code non bastano. In questa guida operativa andiamo oltre le basi: vedrai quando ha senso superare i nodi standard, come scegliere tra esecuzione per item e per tutti gli item, come leggere input/contesto e restituire output corretti, come progettare uno schema stabile per il downstream e implementare pattern avanzati (flatten/unflatten, groupBy, join/lookup, deduplicazione). Tratteremo anche performance (chunking, batching), differenze pratiche tra JavaScript e Python, considerazioni su moduli esterni in ambienti self‑hosted e Cloud, e un approccio solido a debug e gestione errori nel Code node. L’obiettivo: padroneggiare la trasformazione dati in n8n con snippet pronti all’uso e linee guida che rendono i tuoi workflow più affidabili, veloci e manutenibili.

📚 Nuovo a n8n? Parti dalla guida completa: cos’è n8n e come funziona.

[IMG: Editor con nodo “Code” selezionato e menu “Run Once For Each Item / Run Once For All Items” visibile]


Quando superare i nodi no‑code (e perché il Code è la scelta giusta)

I nodi no‑code coprono l’80% dei casi (HTTP Request, Set, IF, Merge, Item Lists, Split In Batches). Ma in alcuni scenari il Code node di n8n è la scorciatoia più pulita:

  • Data shaping non coperto: rinomina massiva di campi, conversioni di tipi, calcoli custom, regole condizionali complesse.
  • Normalizzazioni multi‑fonte: uniformare diversi payload API a uno schema comune prima di un Merge.
  • Filtri/ordinamenti/aggregazioni complessi: preferisci un “punto unico” di verità con codice chiaro anziché proliferare di IF/Switch.

Principio guida:

  • Parti dai nodi standard (meno codice = meno debito tecnico).
  • Inserisci il Code quando hai un “collo di bottiglia” di trasformazione: di solito 20‑60 righe di JS bastano per risolvere in modo espressivo.

Limitazioni da ricordare:

  • Il Code non fa I/O di rete o file system: per chiamate esterne usa “HTTP Request” e passa i risultati al Code.
  • Mantieni lo scope del Code “puro” sui dati: più testabile, meno side‑effect.

Risultato: workflow più leggibili, dove il nodo code n8n svolge un ruolo mirato e documentato, senza sostituire ciò che i nodi nativi già fanno bene.


Esecuzione per item vs per tutti gli item: pattern, trade‑off e insidie

Il Code node supporta due modalità chiave.

  1. Run Once For Each Item
  • Processa un item alla volta.
  • Ideale per mapping di campi, calcoli puntuali, validazioni locali.
  • Output atteso: un singolo item (oggetto con chiave json).

Esempio (per‑item, mapping + calcolo):

// Mode: Run Once For Each Item
const r = $json;
return {
  json: {
    id: r.id,
    title: String(r.title || r.name || '').trim(),
    amount: Number(r.qty || 0) * Number(r.unitPrice || 0),
    createdAt: r.createdAt || r.created_at || null,
  }
};
  1. Run Once For All Items
  • Processa tutti gli item insieme con $input.all().
  • Perfetto per filtri globali, ordinamenti, dedup, groupBy, aggregazioni.
  • Output atteso: un array di item (return items) oppure un singolo item aggregato ({ json: {…} }).

Esempio (all‑items, filtro + sort + limit):

// Mode: Run Once For All Items
const rows = $input.all().map(i => i.json);
const filtered = rows.filter(r => r.status === 'published');
filtered.sort((a, b) => new Date(b.publishedAt) - new Date(a.publishedAt));
const top = filtered.slice(0, 50);
return top.map(j => ({ json: j }));

Trade‑off pratici:

  • Per‑item preserva la cardinalità 1:1 (facile da ragionare).
  • All‑items è più flessibile ma richiede attenzione al formato di ritorno. Se filtri, restituisci solo gli item che restano (“return top.map(…)”).

Insidia tipica: restituire il formato sbagliato. Ricorda:

  • Per‑item: return { json: {…} }
  • All‑items: return [{ json: {…} }, …] oppure return items;

Input, contesto e output coerente: item linking e struttura degli item

Struttura degli item

  • Ogni messaggio è un item: { json: { … }, binary?: { … } }.
  • I nodi scambiano array di item: anche se c’è un solo elemento, è un array di length 1.

Accesso ai dati (built‑in)

  • $json: il JSON del corrente item (in per‑item).
  • $input.all(): tutti gli item in ingresso (in all‑items).
  • $node[“NomeNodo”].json: leggi il json di un nodo precedente per disambiguare fork.
  • $items(): riferimento a più item in contesti particolari.

Esempio (all‑items, arricchire gli item con un campo di provenienza):

const items = $input.all();
const enriched = items.map(it => {
  const j = it.json;
  return { json: { ...j, _sourceNode: $node["HTTP Request"].name || "unknown" } };
});
return enriched;

Item linking: unire dataset

  • Usa il nodo “Merge” (ad esempio “Merge By Key”) per allineare stream diversi sulla stessa chiave (es. id cliente).
  • Nel Code, preparati a ricevere campi combinati e a gestire conflitti di nomi (prefissi o rinomina).

Output coerente

  • Mantieni i nomi dei campi stabili e “case‑sensitive”.
  • Preserva gli identificatori chiave (id, guid) per tracciabilità.
  • Quando fai aggregazioni, valuta se restituire:
  • un array di item (downstream “per‑record”),
  • un singolo item aggregato (downstream “riassunto”).

[IMG: Pannello “Input/Output” del nodo Code con array di item e campi json evidenziati]


Normalizzazione dello schema: flatten/unflatten, mapping e default sicuri

Progettare uno schema stabile

  • Definisci i tipi per campo (string, number, boolean, date ISO) e rispetta la scelta in tutto il flusso.
  • Segna i campi opzionali e fornisci default sicuri (stringa vuota, 0, null).

Flatten JSON e unflatten

  • Utile per esporti tabellari (CSV/Sheets) o per semplificare mapping.

Esempio (per‑item, flatten profondo):

function flatten(obj, prefix = '', out = {}) {
  for (const [k, v] of Object.entries(obj || {})) {
    const key = prefix ? `${prefix}.${k}` : k;
    if (v && typeof v === 'object' && !Array.isArray(v)) {
      flatten(v, key, out);
    } else {
      out[key] = v;
    }
  }
  return out;
}

const f = flatten($json);
return { json: f };

Rinomina massiva e mapping enum

// Per-item: rinomina campi e mappa enum in valori standard
const j = $json;
const statusMap = { active: 'ACTIVE', pending: 'PENDING', disabled: 'DISABLED' };
return {
  json: {
    id: j.id || j._id,
    email: String(j.email || '').toLowerCase().trim(),
    status: statusMap[j.status] || 'UNKNOWN',
    amount: Number(j.amount ?? 0),
    createdAt: j.createdAt || j.created_at || null,
  }
};

Default sicuri e null‑safety

  • Usa coalescenza: j.field ?? default per distinguere tra null/undefined e 0/false validi.
  • Pulisci stringhe con trim(), normalizza maiuscole/minuscole, formatta numeri e date coerentemente.

Benefici: downstream prevedibile, meno condizioni speciali, integrazione più fluida con nodi come “Spreadsheet File” o “Google Sheets”.


Aggregazioni avanzate, groupBy, join/lookup e deduplicazione

GroupBy e aggregazioni in n8n

// All-items: somma vendite per categoria
const rows = $input.all().map(i => i.json);
const agg = {};
for (const r of rows) {
  const k = r.category || 'Uncategorized';
  agg[k] = (agg[k] || 0) + Number(r.amount || 0);
}
const out = Object.entries(agg).map(([category, total]) => ({ json: { category, total } }));
return out;

Finestre temporali e pivot leggeri

  • Filtra per data (es. ultimi 30 giorni), poi aggrega.
  • Crea piccole “pivot” (es. conteggi per stato) restituendo un oggetto riassunto in un singolo item.

Join/lookup tra dataset

  • Preferisci il nodo “Merge” con “Merge By Key” quando possibile.
  • In Code, fai lookup con Map/oggetto indicizzato:
// All-items: join sinistro tra arrA e arrB per key=id
const A = $input.all().map(i => i.json);  // stream A
const B = $node["Normalize B"].json.rows; // es. passato da nodo precedente
const idx = new Map(B.map(b => [b.id, b]));
const joined = A.map(a => ({ ...a, match: idx.get(a.id) || null }));
return joined.map(j => ({ json: j }));

Deduplicazione record n8n (per chiave)

// All-items: dedup per email
const inRows = $input.all().map(i => i.json);
const seen = new Set();
const deduped = [];
for (const r of inRows) {
  const key = String(r.email || '').toLowerCase().trim();
  if (!key || seen.has(key)) continue;
  seen.add(key);
  deduped.push(r);
}
return deduped.map(r => ({ json: r }));

Risultato: dataset compatti, coerenti e pronti per esportazione o analisi, con logiche di business incapsulate in pochi snippet.


Performance, grandi volumi e scelte runtime (JS/Python, moduli esterni)

Performance del Code node

  • Complessità: preferisci passate lineari (O(n)), evita nidificazioni costose. Per join, indice prima (Map) e poi scorri.
  • Chunking/batching: abbina “Split In Batches” per processare gruppi (es. 100/500 item), inserendo attese tra batch se richieste da rate limit a valle.

Pattern batching

  • Pre: sorgente produce array grande → “Item Lists” per splittare in item singoli.
  • Process: “Split In Batches” → Code/HTTP → “Execute Next Batch”.
  • Post: ricomposizione se serve, oppure esportazione diretta.

Scelta tra JavaScript e Python

  • JavaScript: default, veloce, integrazione stretta con $json, $input.all(), return items; ottimo per trasformazioni generiche.
  • Python: utile per calcoli specifici, ma verifica il supporto runtime; in molti casi JS “vanilla” copre l’esigenza con meno attrito.

Moduli esterni in ambiente self‑hosted e Cloud

  • Self‑hosted: puoi avere maggiore controllo su dipendenze e ambienti.
  • Cloud: adotta le capacità di base del Code; per librerie complesse preferisci nodi dedicati o sub‑workflow/servizi esterni.
  • Regola d’oro: se serve una libreria “pesante”, considera di spostare la logica in un servizio o usare nodi nativi che ottimizzano I/O e retry.

[IMG: Canvas con “Item Lists → Split In Batches → Code → HTTP Request → Execute Next Batch”]


Debug efficace e contratti di schema: prevenire errori prima che succedano

Debug e gestione errori nel Code node

  • Log mirati: console.log() con conteggi, chiavi e range; rimuovi i log a fine debug.
  • try/catch con messaggi chiari:
try {
  const items = $input.all().map(i => i.json);
  if (!Array.isArray(items)) throw new Error('Input non array');
  // ... trasformazioni
  return items.map(j => ({ json: j }));
} catch (e) {
  throw new Error(`Code node: ${e.message}`);
}

Contratti di schema

  • Documenta input/output attesi del Code: campi, tipi, opzionalità.
  • Valida e sanitizza all’ingresso: default, trim, cast dei tipi.
  • A valle, usa “IF” per intercettare record invalidi e deviare verso un ramo di correzione o log.

Da JSON annidato a tabella CSV

// Per-item: selezione e ordering campi per export
const j = $json;
const row = {
  id: j.id,
  email: (j.email || '').toLowerCase(),
  country: j.address?.country || '',
  total: Number(j.total ?? 0),
  createdAt: j.createdAt || null,
};
return { json: row };

Merge eventi con finestra temporale

// All-items: dedup per key + finestra recente
const now = Date.now();
const windowMs = 1000 * 60 * 60 * 24 * 7; // 7 giorni
const rows = $input.all().map(i => i.json).filter(r => {
  const t = new Date(r.timestamp || r.createdAt || 0).getTime();
  return !isNaN(t) && (now - t) <= windowMs;
});
const seen = new Set();
const out = [];
for (const r of rows) {
  const key = r.guid || r.id || r.url;
  if (!key || seen.has(key)) continue;
  seen.add(key);
  out.push(r);
}
return out.map(r => ({ json: r }));

Suggerimenti finali:

  • Nomina coerente (snake/camel) e commenti orientati al flusso.
  • Snippet riutilizzabili: crea un “catalogo” interno di ricette (flatten, groupBy, join, dedup).

Quick Takeaways

  • Scegli la modalità giusta: per‑item per mapping/local, all‑items per filtri/ordinamenti/aggregazioni/dedup.
  • Rispetta la struttura: item = { json, binary? }; output coerente con return { json } o return items.
  • Normalizza presto: tipi, default, rinomina massiva e, se serve, flatten/unflatten.
  • Per join/lookup usa “Merge By Key” o indici in Map; per dedup scegli una chiave stabile (email/id/guid).
  • Scala con Item Lists + Split In Batches; riduci complessità con passate lineari e indici.
  • Debug disciplinato (log, try/catch) e contratti di schema evitano regressioni e sorprese a valle.

Conclusione

Il nodo code n8n è il perno della trasformazione dati in n8n quando servono controllo e precisione: ti permette di modellare payload eterogenei in uno schema stabile, aggregare e deduplicare con pochi passaggi, e preparare i dati per nodi downstream o esportazioni. Scegliendo con cura tra esecuzione per item e per tutti gli item, rispettando la struttura degli item e i contratti di schema, riduci drasticamente bug e fragilità. Con pattern come flatten/unflatten, groupBy, join/lookup e dedup, affronti i casi avanzati senza appesantire il canvas. E grazie a batching, codice “vanilla” e debug mirato, mantieni performance e manutenibilità anche su volumi crescenti. Per i marketer, questo si traduce in automazioni più affidabili e insight più puliti, con meno tempo speso a “ripulire” i dati e più tempo dedicato a decisioni e risultati. Inizia dagli snippet e dai pattern di questa guida: il tuo prossimo workflow avrà dati più chiari e un downstream più felice.


FAQ

  1. Quando conviene passare dal no‑code al Code node di n8n?

Quando devi applicare trasformazioni non coperte dai nodi standard: mapping massivo, normalizzazioni complesse, filtri/ordinamenti avanzati o aggregazioni custom. Mantieni però HTTP/FS nei nodi dedicati.

  1. Come scelgo tra esecuzione per item vs tutti gli item?

Usa per‑item per modifiche 1:1 e all‑items per operazioni globali (filtri, sort, dedup, groupBy). Ricorda il formato: per‑item return { json }, all‑items return items.

  1. Come implemento una deduplicazione affidabile?

Definisci una chiave stabile (email/id/guid). In all‑items, usa un Set per tracciare le chiavi viste e restituisci solo i record unici. Se necessario, limita a una finestra temporale.

  1. Posso fare join/lookup senza scrivere molto codice?

Sì, con il nodo “Merge” e modalità “Merge By Key”. In alternativa, indicizza il dataset secondario in una Map e arricchisci gli item primari in un Code all‑items.

  1. Come ottimizzo performance su grandi volumi?

Evita complessità elevate: indicizza prima, scorri poi. Usa “Item Lists” per splittare array e “Split In Batches” per processare chunk, con piccole attese se imposte da rate limit a valle.


Ci dai una mano?

Quale pattern userai per primo nel tuo prossimo flusso: dedup per chiave, join con Merge o normalizzazione con flatten? Se ti è stato utile, condividi questo articolo con il team e raccontaci nei commenti il tuo caso d’uso: arricchiremo la raccolta di snippet per la community!

Articoli correlati

Vuoi automazioni AI su misura per la tua azienda?
Scopri la consulenza →

Partiamo da un processo che oggi vi costa ore

Su WhatsApp risponde una persona, di solito in giornata. Se preferisci scrivere con calma, c’è il modulo qui sotto.

Scrivici su WhatsApp

Raccontaci cosa vuoi automatizzare

Ti rispondiamo noi, di solito in giornata.

Raccontaci cosa vi fa perdere tempo

Due righe bastano. Vi diciamo se si automatizza, come, e quanto costa. Se non conviene, lo diciamo.