最初のワークフロー:手動トリガー → フィールドを編集 → コード
見積もりの件は二年間表計算で手計算してきた:数量×単価、送料を足し、さらに割り戻して単個コストを計算する。二百個の袋、単価一塊八毛五、送料六十、一式で四百三十塊、単個二塊一毛五。数は複雑ではない。問題は、私が送料を二回漏らし、顧客側にはすでに見積書を送ってしまっていたことだ。
その後、この計算ロジックを n8n に移した。三つのノードで、一つの数値を変えて再実行すれば、二秒で新しい価格が出る。この記事は、空白のキャンバスから動作するまでのその三段であり、私が初めて 430 を 37060 と計算してしまった落とし穴も含む。
前提は二つだけ:n8n がインストール済みで開けること(未インストールの場合は『n8n のインストール方法』)、キャンバス、ノードパネル、実行記録の三つに見覚えがあること(不慣れな場合は『インターフェースガイド』)。コードを書ける必要はなく、コードの部分は丸ごとコピーすればよい。
- 三つのノードがそれぞれ一つの役割を担う
- ノード間で受け渡されるものは何か
- 空白のキャンバスから三つのノードまで
- フィールド編集:一つのデータに四つのフィールドを補う
- コードノード:一つを受け取り、一度計算し、一つを返す
- 一度実行し、出力を見る
- 付録:ワークフロー全体の JSON
- どうなれば本当に動作したと言えるか
- 実際に遭遇する五つのエラー
- Code ノードの三つの境界
三つのノードがそれぞれ一つの役割を担う
初心者が最も犯しやすい間違いは、三つのノードを「三つのステップ」と見なすことだ。それらはステップではなく、三つの役割である。
- Manual Trigger(手動トリガー):空のデータを一つ作って下流に送る。データベースを参照せず、リクエストを受け取らず、時間も見ず、純粋に「あなたが一度クリックすると一度実行する」。最初のワークフローでこれを使うのは、変数を一つに減らすためだ——データがどこから来るかはまず気にしなくてよい。
- Edit Fields(フィールド編集):item にフィールドを追加し、または既存のものを変更する。件数は変わらず、入ってきた一件は出ていくときも一件のまま。古いチュートリアルでは Set と呼ばれており、改名してしばらく経つ。2.43.7 のノードパネルには Edit Fields (Set) と書かれており、どちらの名前でも検索できる。
- Code(コード):件数を変更できる唯一のステップ。一件を複数件に分割でき、複数件を一件に圧縮できる。したがってその戻り値は配列でなければならない——これが他のノードとの最大の違いであり、最もエラーが多い箇所でもある。
このインスタンスは 2.43.7 で、UI は簡体字中国語に切り替えています。注意点として、中国語 UI は説明文とボタンだけが翻訳されており、ノード名やパラメータ名は英語のままです。「编辑字段」で検索しても何も出ないので、検索する必要があるのは edit fields。ネット上のチュートリアルにある「Set ノード」「Set ノードの Keep Only Set Fields」も、2.x の UI と照らし合わせると同様に一致しないので、自分を疑わないでください。
ノード間でやり取りされるものは何なのか
これをはっきりさせないと、以降の各エラーは推測に頼るしかない。
n8n でノード間を流れるすべてのデータは配列であり、配列内の各要素は次のような形です:
[
{ "json": { "qty": 200 } },
{ "json": { "qty": 150 } }
]
外側の角括弧は「1 バッチ」で、内側の各オブジェクトが 1 件のデータであり、n8n ではこれを item と呼びます。実際の業務フィールドは json このキーの中にあります。そのため「200 件の注文を処理する」は、このモデルでは 200 回ループすることではなく、1 回でノードに 200 個の item を渡し、ノード自身が 1 つずつ処理することを意味します。
この設計には 2 つの結果があります。良い知らせは、ノードが自然にバッチ処理を行うため、ループを書く必要がないことです。悪い知らせは、コードを書くときに手元にあるのが単一のオブジェクトではなく配列であることです——row.qty この書き方は配列にそのまま使えないので、まず最初の 1 件を取り出す必要があります。
空のキャンバスから 3 つのノードまで
- ワークフロー一覧の右上にある「新建工作流」、またはアドレスバーに直接入力します
/workflow/new。私は後者のやり方に慣れていて、速いです。 - 空のキャンバスで右上にあるものをクリックします +(キャンバス中央のプラス記号をクリックしてもよい)、パネルが「接下来会发生什么?」を表示します。
- 検索ボックスに入力し
manual trigger、Manual Trigger を選択します。 - マウスをノード右側の小さな円点に移動すると、1 つ表示されるので +、それをクリックし、検索し
edit fields、次を選択します: Edit Fields (Set)。この方法で追加すると、接続線は自動でつながり、手動でドラッグする必要はありません。 - もう一度繰り返して検索し
code、Code を選択します。 - ノード名はデフォルトでは英語です。タイトルをダブルクリックすると変更でき、私は中国語に変更しました:手动触发、填写报价单、计算金额。ノードが増えると、英語名を一瞥しただけで Trigger、Set、Code ばかりになるので、中国語に変えるのは純粋に目を休めるためであり、機能上は何の影響もありません。

フィールドを編集:1 件のデータに 4 つのフィールドを追加する
「見積書を入力」をダブルクリックしてパネルを開く。変更するパラメータは 2 か所だけ。
Mode 保持 Manual Mapping、つまりフォーム入力方式です。もう 1 つのオプション JSON Output は JSON を直接書く方式で、ネスト構造を作るときは楽ですが、入門段階ではまだ使わないでください。
Fields to Set に 4 行追加します。各行の左がフィールド名、中央が型のドロップダウン、右が値です:
| フィールド名 | 型 | 值 |
|---|---|---|
| product | 文字列 | 真空圧縮袋 60x80cm |
| qty | 数値 | 200 |
| unit_price | 数値 | 1.85 |
| freight | 数値 | 60 |
型のドロップダウンはデフォルトで「文字列」です。qty、unit_price、freight の 3 つは手動で「数値」に変更する必要があります。UI は止めてくれませんし、選び間違えてもエラーを出さず、静かに 200 を "200" として保存します。この罠がどれほど痛いか、後で計算して見せます。

row.unit_price、1 文字でも少ないと undefined になります。パネルの一番下にある Include Other Input Fields スイッチはデフォルトでオンで、「入力内で自分が触っていないフィールドはそのまま出力する」という意味です。このフローの入力は空なので、スイッチがオンでもオフでも同じです。ただしデータ付きのフローに変えると、これをオフにするのは上流のフィールドをすべて削り、自分で手入力した 4 つだけを残すことになります——そのときコードで product を取得できなくても、コードの書き間違いだと思わないでください。
コードノード:1件を取り、1回計算し、1件を返す
「計算金額」をダブルクリックする。Mode そのままにする Run Once for All Items(配列全体を1回実行)、Language Language は JavaScript のままにする。そして次の部分を編集エリアに貼り付ける:
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 + ' 元',
},
}];
1行ずつ説明する。ハマりどころだけを言う。
items[0].json 最初の1件を取得する。ここにはデータが1件しかないので、[0] を取れば十分だ。複数件の場合は書く items.map(...)、それは次の記事の話だ。items 従来の書き方で、2.x でもまだ使える。新しい書き方は $input.first().json、2種類ともこのインスタンス上で実行した結果は完全に同じだった。私は残している items、なぜなら「配列全体を1回実行」モードでは、手元にあるのがそもそも配列全体なので、この名前のほうが正直だからだ。
toFixed(2) 見栄えのためではない。430 を 200 で割るとちょうど 2.15 で、きれいに見える。送料 55 に変えると 2.175 になり、浮動小数点で計算すると 2.1749999999999998 になる可能性がある。表に書き込んだり顧客に送ったりすると、この末尾は見苦しい。外側の Number() はそれを文字列から数値に戻す——toFixed は文字列を返すので、変換しないと unitCost は表で左揃えになる。
末尾の部分 return が要点だ。配列を返し、各要素を json で1層包む。n8n はこの json キーで「これは業務データ」と「これはバイナリ添付ファイル」を区別する。形式が違うと、ノードがそのまま赤くなる。

1回実行して、出力を見る
キャンバス下部のオレンジ色の「実行」をクリックする。1、2秒で3つのノードの枠が緑になり、各ノードの右上に小さなチェックが付き、接続線の中央に「1 項目」と表示される。

「計算金額」をダブルクリックし、右側の出力エリアを JSON タブに切り替えます:

ついでに誤解しやすい点を言うと、この「実行」ボタンはクリックしたときだけ動きます。Manual Trigger のワークフローは公開されたからといって勝手に動き出すことはなく、「自分で動く」仕組みはありません。定時実行が必要なら、Schedule Trigger のようなトリガーに変更する必要があります。
付録:ワークフロー全体の JSON
ノードをクリックするのが面倒なら、全体をインポートできます。下の部分をコピーし、キャンバスの空白部分で Ctrl+V、3 つのノードがそのままキャンバス上に配置されます。メニューからでも可能です:右上の ⋯ → インポート → ファイルからインポート、まず内容をファイルとして保存します .json。
この部分は私自身、空のワークフローに貼り付けて一度実行してみました:3 つのノード、2 本の接続線、位置はすべて正しく、実行後の amount も 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"}
}
どうなれば本当に動作確認できたとみなせるか
4 項目あり、どれも自分で確認できます。1 つでも欠けたら完了とはみなしません。
- 3 つのノードが緑枠にチェック付きで、2 本の接続線にはいずれも「1 項目」と表示されます。数字が 1 でなければ、途中のノードが件数を変更しているので、後で確認します。
- コードノードの出力 JSON では amount が 430、unitCost が 2.15 です。
- 実行履歴で今回の実行を見つけられます。手動でクリックしたものも記録に残るので、定期タスクだけが一覧に入るわけではありません。
- freight を 60 から 100 に変更して再実行すると、amount は 470 になるはずです。入力を 1 つ変えて出力がそれに追従するのを確認するこの項目は、前の 3 項目より確実です——一度だけ 430 を見ただけでは、偶然の可能性があります。
4 番目の項目は毎回実施することをおすすめします。一度動いたことと正しく動いたことの間には、1 つの隔たりがあります。
実際によく遭遇する 5 つのエラー
1. Code doesn't return items properly
文字列を返しました。私が実測したときは、1 行だけ書いたら return "共 430 元";、ノードがすぐ赤くなり、右下にこのエラーがポップアップ表示されます。

興味深いのは、return { amount: 430 } このように配列で包まず、json で包まない書き方動く。Code ノードは json キーと角括弧を自動で補ってくれる。ドキュメントにもこの動作が明記されている。したがってこのエラーは「フォーマットが十分に標準的でない」のではなく、「返したものがそもそもデータではない」ということ——文字列、数値、null は補えない。
2. items is not defined [line 1]
Mode を選択してしまった Run Once for Each Item、コード内ではまだ使用している items。項目ごとモードでは n8n は一度に1件しか渡さない。現在のこの項目は $json、件数を取得するには $json.qty。2つのモードの違いは一言でいうと、配列全体を一度実行するか、各項目ごとに実行するか。コードを書く前にこのドロップダウンを一瞥すること。
3. 1つのワークフロー内では "Manual Trigger" ノードは1つだけ許可される
すでにトリガーがあるワークフローにさらにトリガーを追加してしまった。今回の私はもっと愚かだった:トリガー付きの JSON の一部を既存ワークフローのキャンバスに貼り付けると、「ノードを挿入できません」が表示され、その下にこの文言が続いた。比較して試したいなら、先に新しいワークフローを開いてから貼り付けること。
4. 出力が undefined だらけになるが、エラーは出ない
Edit Fields 内のフィールド名は unit_price、コード内ではこう書いている row.unitPrice。大文字小文字とアンダースコアが1文字違うだけで、n8n も JS も気にしない。その結果 undefined がそのまま伝播し、summary に「送料込み合計 undefined 元」が現れる。この種の誤りは最も見つけにくい。赤くもならず、音もせず、ただ数字が違うだけだからだ。
5. amount が "37060" になる
フィールド型に文字列を選んだ。60 と "60" は JS では同じに見えるが、 + 文字列に遭遇すると連結に変わる:370 に "60" を加えると "37060" になり、430 にはならない。

5番目はこの記事で最も価値のある項目だ。初めてこの数値が出たとき、37060 を半分ほど見つめてようやく文字列連結だと気づいた——コードはまったく問題なさそうに見えたからだ。問題は前のノードの型ドロップダウンにあった。
Code ノードの3つの境界
Code ノードは n8n 自身のプロセス内で動くが、サンドボックスがある:ローカルファイルは読めず、HTTP リクエストも送れない。ファイルを操作するには Read/Write File From Disk ノードを使い、リクエストを送るには HTTP Request ノードを使う。これは欠陥ではなく、「その辺から貼り付けた JS がどこまでできてしまうか」を最小限に抑えるものだ。
しかしそれが防げない3つのことについては、自分で管理する必要がある。
他人から渡されたワークフロー JSON を安易に貼り付けないこと。貼り付けることは、自分のインスタンス上で他人が書いた JS を実行するのと同じだ。私のこのインスタンスでは JSON を貼り付けると直接ノードとして配置され、確認は表示されず、出所も問われない。本当に試すなら、まず空のテストインスタンスに入れ、コードを確認してから実行するか決めること。
シークレットをコード内にハードコードしないこと。ワークフローは丸ごとエクスポートして、同僚に送ったり、グループに貼ったりできる。コードにハードコードした api key は JSON と一緒に移動する。クレデンシャルノードに置き、n8n に暗号化して保存させるべきだ。
セルフホストではサードパーティの npm パッケージをインストールできる。デフォルトでは無効で、手動で環境変数を有効にする必要がある。有効にすると、Code ノードに任意コード実行の穴を開けることになる。個人利用のインスタンスなら任意だが、複数人で共有するインスタンスでは常に無効のままにすることを勧める。
まとめ
3つのノード、1本のチェーン:トリガーがデータを作り、フィールド編集がデータを補い、コードがデータを計算する。本当に覚えるべきは、この3つのノードの操作方法ではなく、「配列の中に json が入る」形だ。後の IF、Merge、ループ、エラーブランチは、すべてこの形の変種である。
コードは使わなくて済むなら使わない。この見積もりは Edit Fields と式でも計算できる、{{ $json.qty * $json.unit_price + $json.freight }} 1行で済み、ノードも1つ減る。私が最終的に Code を選んだのは、後で3種類の基準の見積もりを同時に計算する必要があり、ノード内に式を積み上げるほうがコードを書くより保守しにくいからだ。1つの数値だけを計算するなら、コードを使うべきではない。
型の落とし穴については、今すぐわざと freight を文字列に変えて一度実行し、430 が 37060 になるのを自分の目で見ることを勧める。文章を10回読むより、自分で1回間違えるほうがよい。
続けて次へ
前回の記事は『n8n、Zapier、Make の選び方』。ノード、接続、実行の3つが JSON の中でどのような形になるかは、この記事で分解した。サービスが起動しない、port が衝突したときは、次を参照:『n8n の起動エラーと port 占有の調べ方』。インストールはこの記事、画面に不慣れならこの記事。コース全体の目次はここ。
参考資料
- Manual Trigger:実行をクリックしたときだけ動作し、自動トリガーは提供しない;1つのワークフローに1つだけ許可される
- Edit Fields (Set):Manual Mapping と JSON Output の2つのモードにおける Include in Output の役割
- Code:2つの Mode の違い、言語オプション、ファイルシステムにアクセスできず HTTP リクエストを発行できないこと
- n8n のデータ構造を理解する:配列の中に json が入る由来、および Code ノードが json キーを自動で補う説明
- 組み込みショートカットを使用する:式内の組み込み変数とメソッドのうち、どれが Code ノードで適用されないか
最終更新:2026年10月28日、使用しているのは n8n 2.43.7。

