初心者向け

n8n Codeノードの使い方:JavaScriptでデータを加工する

n8nのCodeノードの使い方を、実際に動かして確認した結果とあわせて解説します。2つの実行モードの違い、戻り値の形式、そして中でHTTPリクエストができない理由まで。

動作確認: — n8n 2.36.8 / Code ノード v2

用意されたノードでは足りない加工をしたいときに使うのが Codeノードです。 JavaScript(または Python)を書いて、データを自由に変形できます。

この記事は前半がn8n を触ったことがない人向けで、実際にコードを書いて データを整形するところまでを通します。後半は基本操作ができる人向けに、 実行モードの違いと、Codeノードの中でできないことを扱います。

この記事の内容は n8n 2.36.8 / Code ノード v2 で実際にコードを実行して確認しています。 推測ではなく、実行結果に基づいて書いています。

Codeノードは何をするものか

前のノードから受け取ったデータを、コードで加工して次に渡すノードです。

n8n には Edit Fields(Set)や Filter のような加工用ノードがありますが、 それらの組み合わせでは表現しにくい処理――入れ子の配列を展開する、 複数の値から新しい値を計算する、件数そのものを変える――はコードの方が簡単です。

逆に、単純な値の設定や条件分岐は専用ノードの方が読みやすいので、 何でもコードで書くのは避けた方がいいです。ワークフローを開いたときに、 何をしているかが一目で分からなくなります。

実際に書いてみる

前回までの記事で使った気象庁のデータを加工します。

このJSONは地域ごとの天気が入れ子の配列になっていて、そのままでは扱いにくい形です。 これを「1地域=1件」のフラットなデータに展開します。

手順

  1. Get Tokyo Forecast(HTTP Request)の後ろに Code ノードを追加する
  2. Mode は Run Once for All Items(既定)のまま
  3. Language は JavaScript(既定)のまま
  4. コード欄に次を書く
const results = [];

for (const item of $input.all()) {
  const areas = item.json.timeSeries?.[0]?.areas ?? [];
  for (const area of areas) {
    const weather = area.weathers?.[0] ?? '';
    results.push({
      area: area.area.name,
      weather,
      isRainy: weather.includes('雨'),
    });
  }
}

return results.map((r) => ({ json: r }));
  1. Execute step を押す
Codeノードの編集画面。ModeにRun Once for All Items、LanguageにJavaScript、その下にコードエディタが表示されている
Mode と Language を選び、その下のエディタにコードを書く

実行すると7件になった

実行結果がこれです。入れ子だったデータが、1行1件のフラットな形に展開されました。

Codeノードの実行結果。左に入力データの階層、中央にコード、右の出力テーブルに7件のデータが表示され、東京地方はisRainyがtrue、他はfalse、うち3件のweatherがemptyになっている
左が入力、右が出力。7件のうち3件は weather が空になっている

ここで予想と違うことが2つ起きています。件数が想定より多く、 一部の行の weather が空です。これは設定ミスではなく、 データの構造を理解していなかったことが原因でした。次の節で説明します。

前のデータを受け取る書き方

コードの中で使える変数は、モードによって変わります。

書き方 意味
$input.all() 入力の全件を配列で取得(All Items モード)
$json 処理中の1件のデータ(Each Item モード)
$('ノード名').all() 指定した名前のノードの出力を取得

$input.all() が返すのは、{ json: {...} } という形のアイテムの配列です。 中身を取り出すには item.json.フィールド名 と書きます。

2つの実行モードの違い

Mode で2つから選べます。ここを間違えると、書いたコードがそもそも動きません。

入力が3件あるときRun Once for All Items(既定)3件をまとめて受け取り、コードは 1回 だけ動く$input.all()で全件を配列として扱う集計、並べ替え、件数を変える処理に向くRun Once for Each Item1件ずつ受け取り、コードは 3回 動く$jsonでその1件だけを扱う1件ごとの変換に向く。全件をまたぐ集計はできない
どちらを選ぶかで、コードの書き方(扱える変数)が変わる。

Run Once for All Items(既定)は、入力が何件あってもコードは1回だけ動きます。 全件を $input.all() で受け取るので、集計や、件数を変える処理ができます。

Run Once for Each Item は、入力の件数だけコードが繰り返し動きます。 その回で扱うデータは $json で参照します。1件ごとの単純な変換に向いています。

迷ったら All Items のままで問題ありません。1件ずつ処理したい場合も $input.all() をループで回せば同じことができます。

戻り値の形式

多くの解説で「必ず [{ json: {...} }] の形で返すこと」と書かれています。 実際に試したところ、それ以外の形でも動きました。

n8n 2.36.8 / Code ノード v2 で確認した結果です。

返した値 結果
[{ json: { a: 1 } }] 正常。そのまま1件のデータになる
[{ name: 'A' }, { name: 'B' }] 正常。自動で json に包まれ、2件になる
{ name: 'single' } 正常。配列でなくても1件のデータになる

つまり n8n が形式を補完してくれます。

ただし、明示的に { json: ... } を付けて返すことを勧めます。理由は2つあります。

  • バイナリデータを一緒に返したいとき({ json: ..., binary: ... })は、この形でないと書けない
  • 読んだ人が「これは1件のデータだ」と判断しやすい

「エラーになるから付けなければいけない」のではなく、意図を明確にするために付ける、 という理解が正確です。

Codeノードの中ではHTTPリクエストができない

これが一番引っかかる点です。Codeノードのサンドボックスにはネットワーク機能がありません。

実際に確認した結果です。

試したこと 結果
typeof fetch "undefined"
fetch('https://example.com') ERROR: fetch is not defined
typeof XMLHttpRequest "undefined"
typeof process "undefined"
typeof require "function"(存在はする)
require('http') ERROR: Module 'http' is disallowed

require 自体は存在するのに、モジュールの読み込みが拒否されます。 このエラーメッセージが出たら、原因はこれです。

process も使えないので、環境変数をコードから直接読むこともできません。

ではどうするか

HTTP Request ノードを使って、その出力を Code ノードで加工します。 この記事の例がまさにその形です。

HTTP Request(通信する)  →  Code(受け取ったデータを加工する)

「Codeノードの中で全部やる」のではなく、通信はノードに任せて、コードは変形だけ、 と役割を分けるのが n8n の設計です。

実際に起きたこと:件数が想定と違う

最初は「東京都の4地域だから4件になる」と考えていました。実際は7件で、 そのうち3件は weather が空でした。

出力テーブルの拡大。東京地方・伊豆諸島北部・伊豆諸島南部・小笠原諸島の4件に天気が入り、続く東京地方・伊豆諸島・小笠原諸島の3件はweatherがemptyと表示されている
上の4件には天気が入っているが、下の3件は空になっている

原因は2つ重なっていました。

1. レスポンスが配列だと、n8nは複数のアイテムに分割する

気象庁のJSONは、トップレベルが2要素の配列です。

[
  { "publishingOffice": "気象庁", "timeSeries": [ ... ] },   // 3日予報
  { "publishingOffice": "気象庁", "timeSeries": [ ... ] }    // 週間予報
]

HTTP Request ノードは、配列で返ってきたレスポンスを1要素ずつのアイテムに分けます。 入力パネルにも 2 items と表示されています。

つまり $input.all() は2件を返し、ループが2回回ります。

2. 2件目は構造が違う

2件目は週間予報で、weathers という項目を持っていません。

1件目(3日予報) 2件目(週間予報)
areas の数 4 3
areas の中身 area, weatherCodes, weathers, winds, waves area, weatherCodes, pops, reliabilities

コードでは area.weathers?.[0] ?? '' と書いていたので、 weathers が無い2件目は空文字になり、そのまま3件が出力されました。 4 + 3 = 7件、という内訳です。

どう直すか

やりたいことが「今日明日の天気」なら、1件目だけを対象にするのが正しい書き方です。

// 1件目(3日予報)だけを使う
const forecast = $input.first().json;
const areas = forecast.timeSeries?.[0]?.areas ?? [];

return areas.map((area) => {
  const weather = area.weathers?.[0] ?? '';
  return { json: { area: area.area.name, weather, isRainy: weather.includes('雨') } };
});

この失敗から学べることは、?? '' のような既定値は便利だが、 「データが無い」ことを黙って隠してしまうという点です。 空文字のまま処理が続くので、エラーにならずに間違った結果が出ます。

想定と違う件数が出たら、まず入力が何件なのかを確認してください。 入力パネルの右上に件数が出ています。

使いどころの目安

コードで書くべきか、専用ノードを組み合わせるべきかの判断です。

Codeノードが向いている

  • 入れ子の配列を展開する(この記事の例)。ただし展開するだけなら Split Out の方が読みやすい
  • 複数の値から計算して新しい値を作る
  • 件数そのものを変える(絞り込み、分割、まとめる)

専用ノードの方がよい

  • 単純な値の設定 → Edit Fields(Set)
  • 条件で分ける → IF / Switch
  • 件数を絞る → Filter / Limit
  • 通信する → HTTP Request

ワークフローは他人(半年後の自分を含む)が読むものです。 キャンバスを見ただけで流れが分かる状態を保つ方が、結果的に早く直せます。

うまくいかないときの切り分け

  1. モードが合っているか — $json は Each Item、$input.all() は All Items
  2. item.json を経由しているか — $input.all() の要素は { json: ... } の形
  3. 通信しようとしていないか — fetch も require('http') も使えない
  4. 入れ子が存在しない場合を考えているか — ?. と ?? で空のときに落ちないようにする
  5. 入力の件数を見る — 入力パネル右上に件数が出る。 APIが配列を返すと、n8nは自動で複数アイテムに分割する
  6. ?? '' が失敗を隠していないか — 項目が無いのに空文字で処理が続いていないか

次に読む

次に読む