n8nで組んでいて手が止まるのは、ノードの設定より「前のノードの値をどう書いて取り出すか」のほうです。この記事では、Webサイトの問い合わせをGoogleスプレッドシート「問い合わせ一覧」に残し、Slackの #問い合わせ に知らせる「問い合わせ受付」ワークフローを例に、データの形、式の書き方、日付・文字列・数値・配列の変換、Edit Fields (Set) での整え方を通します。前提は「n8nの使い方入門:最初のワークフローを作って動かす」の3ノードが動いていて、入口が「n8nで外部サービスとつなぐ:Webhook・HTTP Request・API」のWebhookになっていることです。版は2026年10月時点の安定版2.44.7で書いています。
この記事の内容
先に決めること
値を整える場所を1か所に寄せる
式はどのノードのどの欄にも書けます。便利な反面、Google Sheetsの列に .trim()、Slackの本文にも .trim() と散らすと、直すたびに全部のノードを開いて回ることになります。公式のドキュメントも、変換だけが目的なら Edit Fields (Set) にまとめるよう勧めています。線引きは次のとおりです。
| やること | 置き場所 |
|---|---|
| 空白を落とす、形式を揃える、名前を付け直す | トリガーの直後に置く Edit Fields (Set) 1つ |
| 1つの欄にだけ値をはめる(Slackの本文、メールの件名) | その欄の式 |
| 配列を1件ずつに分ける、まとめる、並べ替える | Split Out・Aggregate・Sort などの専用ノード |
| 複数のitemを見比べる、外部のライブラリを使う | Codeノード |
タイムゾーンを Asia/Tokyo に揃えておく
$now などの日付は、ワークフローのタイムゾーンで計算されます。何も設定しないとアメリカ東部時間(America/New_York)です。セルフホストは環境変数 GENERIC_TIMEZONE、n8n Cloudは管理画面の時刻の設定、ワークフローごとは「Settings」の「Timezone」で揃えます。手順は「n8nの使い方入門:最初のワークフローを作って動かす」、Codeノードの中まで揃える話は「n8nをセルフホストで導入する:Docker ComposeでVPSに立て、独自ドメインとHTTPSで使う」に書きました。ここが揃っていないと、この記事の日付の式はすべて13〜14時間ずれます。
ノード名を先に決める
式は $('受付データを整える') のようにノード名で前のノードを呼びます。同じワークフローの中で名前を変えれば、n8nが参照している式も一緒に書き換えます。ただし、ノードを別のワークフローへコピーしたときは書き換わらず、参照が切れます。ノード名は役割が分かる日本語にして、作ったあとはなるべく変えません。
n8nのデータの形
ノードの間を流れるデータは、いつも「itemの配列」です。1つのitemの中に、普通の値を入れる json と、ファイルがあればその中身を入れる binary があります。OUTPUTを「JSON」の見え方にすると、json の中身だけが配列で並んで見えます。
自社サイトのフォームからWebhookに届いた問い合わせは、こう見えます。
[
{
"headers": { "content-type": "application/json" },
"params": {},
"query": {},
"body": {
"company": " 株式会社サンプル ",
"name": "山田\t太郎",
"email": "Yamada@Example.com",
"category": "お見積もり",
"employees": "30",
"message": "料金表を送ってください。\n導入時期は来月です。",
"contact": { "tel": "03-1234-5678", "department": "総務部" },
"services": ["問い合わせ受付", "日報集計"],
"sentAt": "2026-10-26T05:05:12.000Z"
},
"webhookUrl": "https://n8n.example.co.jp/webhook-test/inquiry",
"executionMode": "test"
}
]
| 部分 | 中身 | 式での取り方 |
|---|---|---|
| 配列全体 | ノードが出した結果の全部 | $input.all()、$('ノード名').all() |
| item | 配列の1つ。後ろのノードはitemごとに1回動く | $input.item、$('ノード名').item |
| json | itemの値。入れ子(オブジェクト)や配列も入る | $json.body.company |
| binary | 添付ファイルや画像。data という名前で入ることが多い | $binary.data.fileName |
| 対応の印(pairedItem) | どの入力itemから作られたか。画面には出ない | .item が前のノードを辿るのに使う |
フォームの値は body の下、contact はさらにその下、services は配列です。employees の30は数字に見えますが、"30" と引用符が付いているので文字列です。この入れ子と型の違いが、この記事で扱うつまずきのほとんどです。
itemの数はノードごとに変わります。フォーム1回のWebhookは1件ですが、Google Sheetsで未対応の行を10行読めば10件になり、後ろのSlackは10通送ります。1通にまとめる書き方は応用で扱います。

式で使うものの一覧
式は欄に {{ }} で書き、中身はJavaScriptです(Pythonは式では使えません)。欄の上で「Fixed」(固定値)と「Expression」(式)を切り替え、Expressionにすると欄の下に「Result」(計算結果)が出ます。値が無いと [undefined]、空の文字なら [empty] と出ます。
| 書き方 | 何を指すか | 使う場面 |
|---|---|---|
$json | 直前のノードから来た、いま処理中のitemの値 | 直前のノードの値を使う |
$('ノード名').item.json | 指定したノードの、いまのitemの元になったitem | 2つ以上前のノードの値を使う |
$('ノード名').first().json | 指定したノードの先頭のitem | 何件あっても先頭だけで足りるとき |
$('ノード名').all() | 指定したノードの全item | 全件を並べる、数える |
$('ノード名').isExecuted | そのノードが動いたか(true/false) | 分岐の片側だけ動くとき |
$input.item $input.first() $input.all() | 直前のノードのitem・先頭・全件 | $json と同じ。全件は $input.all() |
$now $today | いまの日時 / 今日の0時(Luxonの日時) | 受付日時、期限の計算 |
$itemIndex | いま処理中のitemが何番目か(0から) | 番号を振る、.all()[$itemIndex] |
$execution.id $workflow.name | 実行のIDとワークフロー名 | エラー通知に添える |
$vars.名前 | Variables(変数)の値 | 送り先などの共通の値 |
$ifEmpty(値, 代わり) | 値が空なら代わりを返す | 未入力の補い |
$vars のVariablesは、n8n CloudのPro・Enterprise、セルフホストのBusiness・Enterpriseで使える機能です(2026年10月時点)。値はすべて文字列になります。
どれを使うかは、次の順で決めます。
- 直前のノードの値なら
$json - 2つ以上前なら
$('ノード名').item.json .itemでエラーになる場所(分岐の合流やCodeノードの後ろ)なら$('ノード名').first().jsonか$('ノード名').all()[$itemIndex].json- 全件を1つの文にまとめるなら
$input.all()と、ノードの「Settings」の「Execute Once」
式は手で打たずに、INPUTから欄へドラッグして作るのが確実です。INPUTには前にあるノードが一覧で並び、Webhookのような2つ以上前のノードも開いて項目をドラッグできます(TableやJSONの表示では、上のノード名の選択欄で切り替えます)。直前のノードからなら {{ $json.company }}、それより前なら {{ $('Webhook').item.json.body.company }} の形で入ります。項目名が日本語や記号を含むときは $json['会社名'] のように角かっこで入ります。

手順:届いた問い合わせを Edit Fields (Set) で整える
届いたJSONの道筋を確かめる
Webhookノードで「Listen for test event」を押し、上のJSONの body の中身をcurlで送ります。送り方は「n8nで外部サービスとつなぐ:Webhook・HTTP Request・API」と同じです。OUTPUTをJSONの見え方にし、body の中に値が入っていることを確かめてから次へ進みます。
Edit Fields (Set) を置いて項目を作る
先に「問い合わせ一覧」の1行目に「電話番号」「従業員数」「希望サービス」の3列を足しておきます。Edit Fields (Set) で作る項目名をシートの見出しと同じにしておくと、後ろのGoogle Sheetsで「Map Automatically」(項目名と見出しが同じ列に自動で入れる)が使え、列ごとに式を書かずに済みます。
- Webhookの右の + を押し、「Edit Fields (Set)」を追加する
- ノード名を「受付データを整える」に変える
- 「Mode」は「Manual Mapping」のままにする
- INPUTの
bodyを開き、companyを「Fields to Set」の「Drag input fields here」へドラッグする - 名前を「会社名」に直し、値の式の末尾に
.trim()を足す - 「Add Field」で残りの項目を足し、下の表のとおり名前・型・値を入れる
- 「Include Other Input Fields」はオフのままにする(公式ドキュメントでは旧表記の「Keep Only Set Fields」「Include in Output」で書かれている)
- 「Execute step」を押し、OUTPUTに10項目だけが並んでいることを確かめる
| 名前 | 型 | 値 |
|---|---|---|
| 受付日時 | String | {{ $now.toFormat('yyyy-MM-dd HH:mm') }} |
| 会社名 | String | {{ $json.body.company.trim() }} |
| お名前 | String | {{ $json.body.name.replace(/[\t\r\n]+/g, ' ').trim() }} |
| メールアドレス | String | {{ $json.body.email.trim().toLowerCase() }} |
| 種類 | String | {{ $ifEmpty($json.body.category, 'その他') }} |
| 内容 | String | {{ $json.body.message.trim() }} |
| 電話番号 | String | {{ $json.body.contact?.tel ?? '' }} |
| 従業員数 | Number | {{ $json.body.employees }} |
| 希望サービス | String | {{ ($json.body.services ?? []).join('、') }} |
| 対応状況 | String | 未対応(Fixedのまま) |
「Include Other Input Fields」をオフにすると、出力はここで作った項目だけになり、headers などの要らない値が後ろへ流れません。届いた値も全部残したいときだけオンにします。オフのまま後ろのノードで $json.body.company と書くと空になります。そのときは $('Webhook').item.json.body.company で取りに行きます。

型を選ぶ
各項目の左にある型は「String」「Number」「Boolean」「Array」「Object」「Binary Data」から選べ、選んだ型に変換して出力します。2.44.7で試した結果は次のとおりです。
| 届いた値 | 選んだ型 | 結果 |
|---|---|---|
"30" | Number | 30(数値になる) |
"1,200,000" | Number | エラー('予算' expects a number but we got '1,200,000') |
""(空) | Number | 0 になる |
"true" | Boolean | true |
"はい" | Boolean | エラー |
"03-1234-5678" | Number | エラー。ハイフンを落としても先頭の0が消えるのでStringにする |
カンマ付きの金額は、{{ $json.body.budget.replaceAll(',', '').toNumber() }} のように式でカンマを落としてからNumberにします。空欄が0になるのは見落としやすく、「従業員数0」の行がシートに並びます。未入力を区別したい項目はStringのまま残します。エラーにせず型の変換だけゆるめたいときは、「Add option」から「Ignore Type Conversion Errors」を足します。
入れ子のJSONを平らにする
Google Sheetsの列やSlackの本文は、入れ子を受け付けません。body.contact.tel のように奥にある値は、表の「電話番号」のように1段の項目へ取り出します。これが「平らにする」作業です。取り出し方は値の形で決まります。
| 届いた形 | やり方 | 例 |
|---|---|---|
| オブジェクトの中の値 | 項目を1つ作り、パスで取り出す | {{ $json.body.contact.tel }} |
| 文字や数字の配列 | 区切り文字でつないで1つの文字にする | {{ $json.body.services.join('、') }} |
| オブジェクトの配列(明細など) | 「Split Out」の「Fields To Split Out」に配列の項目名を入れ、1件ずつのitemにする | body.items |
| 項目が多いオブジェクト | 「Mode」を「JSON」にして形をまとめて書く | 下の例 |
JSONモードではこう書きます。
{
"会社名": {{ JSON.stringify($json.body.company.trim()) }},
"電話番号": {{ JSON.stringify($json.body.contact.tel) }},
"部署": {{ JSON.stringify($json.body.contact.department) }},
"内容": {{ JSON.stringify($json.body.message) }}
}
文字の値を JSON.stringify() で包むのは、" や改行でJSONが崩れるのを防ぐためです。2.44.7のEdit Fieldsは多少崩れても直して読みますが、HTTP Requestの本文では「The value in the “JSON Body” field is not valid JSON」で止まるので、どこでも包む癖をつけておきます。
名前に . を入れると入れ子になる点にも気をつけます。名前を 連絡先.電話番号 にすると、{"連絡先": {"電話番号": ...}} という入れ子が出力されます。点を含む名前のまま出したいときは「Add option」から「Support Dot Notation」を足してオフにします。
後ろのノードから使う
- 「問い合わせ一覧に追加」(Google Sheets)を開き、「Mapping Column Mode」を「Map Automatically」に変える
- 「Execute step」を押し、シートの10列に値が入ったことを確かめる
- Slackの「Message Text」を下に変える
新しい問い合わせが届きました
会社名: {{ $('受付データを整える').item.json['会社名'] }}
お名前: {{ $('受付データを整える').item.json['お名前'] }}
種類: {{ $('受付データを整える').item.json['種類'] }}
希望: {{ $('受付データを整える').item.json['希望サービス'] || '(未選択)' }}
Slackの直前はGoogle Sheetsなので、$json ではなくノード名で「受付データを整える」を指名します。

日付を扱う(Luxon)
n8nの日付は、Luxonという日付ライブラリの DateTime で扱います。$now と $today は最初から DateTime です。ノードからノードへ渡るときは文字列になるので、前のノードの日付で計算するときは、いったん DateTime に読み直します。
| やりたいこと | 書き方 | 結果の例 |
|---|---|---|
| いまを表示する | {{ $now.toFormat('yyyy-MM-dd HH:mm') }} | 2026-10-26 14:05 |
| 曜日を日本語で付ける | {{ $now.setLocale('ja').toFormat('M/d(EEE)') }} | 10/26(月) |
| ISO形式の文字列を読む | {{ DateTime.fromISO($json.body.sentAt) }} | ワークフローの時刻に直して読む |
| 書式が決まった文字列を読む | {{ DateTime.fromFormat('2026/10/26 14:05', 'yyyy/MM/dd HH:mm') }} | 2026-10-26T14:05:00.000+09:00 |
| 3日後 | {{ $now.plus(3, 'days').toFormat('yyyy-MM-dd') }} | 2026-10-29 |
| 7日前 | {{ $today.minus(7, 'days').toFormat('yyyy-MM-dd') }} | 2026-10-19 |
| 月初・月末 | {{ $now.startOf('month').toFormat('yyyy-MM-dd') }} | 2026-10-01 |
| 2つの日付の差(日数) | {{ $now.diff(DateTime.fromISO('2026-10-20'), 'days').days }} | 6.58 など |
| 日本時間に直す | {{ $json.body.sentAt.toDateTime().setZone('Asia/Tokyo') }} | 2026-10-26T14:05:12.000+09:00 |
書式の記号は大文字と小文字で意味が変わります。MM は月、mm は分、HH は24時間の時、hh は12時間の時です。yyyy-mm-dd と書くと月の位置に分が入り、毎日日付がおかしくなります。
時差では2か所でつまずきます。1つは、末尾が Z(世界標準時)の文字列に .toDateTime() を付けると、世界標準時のまま読まれることです。2.44.7で試すと、"2026-10-26T05:05:12.000Z".toDateTime().toFormat('yyyy-MM-dd HH:mm') は「2026-10-26 05:05」になり、DateTime.fromISO() で読むと「2026-10-26 14:05」になりました。外から届いた日時は DateTime.fromISO() で読むか、.setZone('Asia/Tokyo') を付けてから整形します。
もう1つは、DateTime を文字とつなぐと数字になることです。{{ '受付: ' + $now }} は「受付: 1793012522853」のようなミリ秒の数字になります。文字とつなぐ前に .toFormat() を付けます。
式では format() も使えますが、n8nが式のために足したものでCodeノードでは動きません。両方で通じる toFormat() に揃えておきます。日付だけを扱うなら、式を書かずに「Date & Time」ノード(「Format a Date」「Add to a Date」「Get Time Between Dates」など)を使う手もあります。

文字列・数値・配列・JSONのよく使う書き方
n8nはJavaScriptの書き方に加えて、式のための関数を足しています。値の後ろに . を打つと候補が出ます。
| やりたいこと(文字列) | 書き方 | 結果 |
|---|---|---|
| 前後の空白・改行を落とす | $json.body.company.trim() | 株式会社サンプル |
| タブ・改行を半角スペースに | .replace(/[\t\r\n]+/g, ' ') | 山田 太郎 |
| 全部置き換える | .replaceAll('-', '') | 0312345678 |
| 小文字に揃える | .toLowerCase() | yamada@example.com |
| 1行目だけ | .split('\n')[0] | 料金表を送ってください。 |
| メールの形か | .isEmail() | true |
| HTMLのタグを消す | .removeTags() | <p>本文</p> が「本文」に |
| 全角英数字を半角に | .normalize('NFKC') | ABC123 が ABC123 に |
| やりたいこと(数値・真偽) | 書き方 | 結果 |
|---|---|---|
| 文字を数値に | $json.body.employees.toNumber() | 30 |
| カンマ付きを数値に | .replaceAll(',', '').toNumber() | 1200000 |
| 3桁区切りで表示 | (1200000).format('ja-JP') | 1,200,000 |
| 小数第1位で丸める | (1.256).round(1) | 1.3 |
| 文字を真偽に | $json.body.agree.toBoolean() | “true” が true、”false”・”0″・”no” が false |
| やりたいこと(配列) | 書き方 | 結果 |
|---|---|---|
| つないで1つの文字に | $json.body.services.join('、') | 問い合わせ受付、日報集計 |
| 件数 | .length | 2 |
| 含むか | .includes('日報集計') | true |
| 空を除く | .compact() | null や “” が消える |
| 重複を除く | .unique() | 同じ値が1つに |
| オブジェクトの配列から1項目だけ | .pluck('company') | 会社名だけの配列 |
| 合計 | .sum() | 数値の配列だけ。文字が混ざるとエラー |
| やりたいこと(オブジェクト・JSON) | 書き方 | 結果 |
|---|---|---|
| 無いかもしれない値を安全に取る | $json.body.contact?.tel ?? '' | 無ければ空 |
| 空なら代わりの値 | $ifEmpty($json.body.category, 'その他') | その他 |
| JSONの文字列にする | JSON.stringify($json.body.contact) | {“tel”:”03-1234-5678″,…} |
| JSONの文字列を読む | $json.raw.parseJson() | オブジェクトに戻る |
| 条件で値を変える | $json.body.category === 'お見積もり' ? '営業' : 'サポート' | 営業 |
オブジェクトをそのまま文字とつなぐと [object Object] になります。Slackの本文に入れ子をそのまま出したいときは JSON.stringify() で文字にします。日本語の全角・半角や文字化けの扱いは「n8nを日本語で使う:画面の言語、日本語化の現状と、日本語データでつまずくところ」に分けました。
応用
毎朝、未対応の件数と会社名を1通で送る
Schedule Triggerで毎朝9時に動かし、Google Sheetsの「Get row(s) in sheet」で「対応状況」が「未対応」の行を読むと、行の数だけitemが出ます。そのままSlackにつなぐと10件なら10通届くので、Slackノードの「Settings」で「Execute Once」をオンにし、本文で全件を読みます。
未対応の問い合わせが {{ $input.all().length }} 件あります
{{ $input.all().map(i => '・' + i.json['会社名'] + '(' + i.json['受付日時'] + ')').join('\n') }}
Execute Onceは最初のitemで1回だけ動く設定で、$input.all() はそのときも全件を返します。定期実行の組み方は「n8nの定期実行とサブワークフロー:Schedule Triggerと部品化」で扱います。


何行もの処理を式に書く
式は1つの値を返す形でしか書けず、const で変数を置くと「invalid syntax」になります。どうしても途中の値を置きたいときは、関数で包んですぐ呼ぶ形(即時実行関数)にします。
{{ (() => {
const company = $json.body.company.trim();
const dept = $json.body.contact?.department ?? '';
return dept ? `${company}(${dept})` : company;
})() }}
この形が3行を超えたら、Codeノードへ移す合図です。
種類で分けるのは式ではなくIF・Switchで
? : で値を入れ替えるのは式で足ります。通知先を変えるなど処理そのものを分けるときは、IFやSwitchで組んだほうが画面で流れが追えます。組み方は「n8nの分岐とループ:IF・Switch・Merge・Loop Over Items」に書きました。
できないことと、その代わり
| できないこと | 理由 | 代わりの手 |
|---|---|---|
| 式でPythonを書く | 式はJavaScriptだけ | Codeノードで「Python」を選ぶ |
式で const などの文を並べる | 式は値を1つ返す形だけ | 即時実行関数で包むか、Codeノードへ |
| 前のitemの計算結果を次のitemで使う | 式はitemごとに毎回まっさらに計算される | Aggregate・Summarizeでまとめるか、Codeノード |
式で環境変数($env)を読む | 2.0から既定で止められ、「access to env vars denied」になる | 共通の値はVariables、秘密の値はCredentialに置く |
| 重い計算を式で回す | セルフホストの既定では1回の計算が5秒で打ち切られる(N8N_EXPRESSION_ENGINE_TIMEOUT) | Codeノードに移す |
Codeノードで format() や plus(3, 'days') を使う | n8nが式のために足した書き方で、Codeノードでは使えない | toFormat()、plus({ days: 3 }) と書く |
よく詰まるところ
| 症状 | 原因 | 直し方 |
|---|---|---|
Resultが [undefined] で、本番でも空のまま流れる | 項目名の打ち間違いや大文字小文字の違い。2.44.7では存在しない項目にメソッドを続けてもエラーにならず空になる | INPUTからドラッグして作り直す。Webhookなら body の下か確かめる |
| 2つ前のノードの値が取れない | $json は直前のノードしか指さない | $('ノード名').item.json で指名する |
| 「Referenced node doesn’t exist」 | ノード名の打ち間違い、または別のワークフローからコピーしてきて名前が違う | INPUTからドラッグし直し、式のノード名を今の名前に揃える |
| 「Node ‘〜’ hasn’t been executed」、または「Can’t get data for expression」 | 参照先のノードがまだ動いていない状態で「Execute step」を押した | INPUTの「Execute previous nodes」を押すか、前のノードをピン留めする |
| 「Multiple matching items」や「is on another branch」 | .item で辿る先が複数ある、または別の分岐にある | .first()、.last()、.all()[$itemIndex] に変える |
Codeノードの後ろで .item がエラーになる | Codeノードが新しいitemを作り、元のitemとの対応の印を返していない | Codeノードで対応を返すか、.first() に変える。書き方はCodeノードの記事へ |
| 30+1 が 301 になる | フォームの値は数字でも文字列 | .toNumber() を付けるか、Edit Fieldsで型をNumberにする |
| 「〜 expects a number but we got ‘1,200,000’」 | 型をNumberにした項目にカンマや単位が入っている | .replaceAll(',', '') で落としてから渡す |
| 未入力のはずの従業員数が0で入る | 型Numberは空の文字を0にする | 未入力と区別したい項目はStringにする |
| 受付日時が9時間ずれる | Z 付きの日時を .toDateTime() で読んで世界標準時のまま整形した | DateTime.fromISO() で読むか .setZone('Asia/Tokyo') を付ける |
| 受付日時が13〜14時間ずれる | タイムゾーンが初期値のAmerica/New_York | GENERIC_TIMEZONE かワークフローの「Timezone」を Asia/Tokyo にする |
| 日付が「1793012522853」のような数字になる | DateTime をそのまま文字とつないだ | .toFormat('yyyy-MM-dd HH:mm') を付けてからつなぐ |
Slackに [object Object] と出る | オブジェクトをそのまま文字にした | 中の値をパスで取り出すか JSON.stringify() で包む |
Slackに {{ $json.company }} がそのまま届く | 欄が「Fixed」のまま式を貼った | 欄を「Expression」に切り替える |
詰まったら、まずOUTPUTをJSONの見え方にして、値がどの階層に、どの型で、何件入っているかを見ます。式の問題の大半は、ここを見れば原因が分かります。

次にやること
- n8nの使い方入門:最初のワークフローを作って動かす
- n8nの分岐とループ:IF・Switch・Merge・Loop Over Items
- n8nのCodeノード:JavaScriptとPythonで足りないところを書く
- n8nで外部サービスとつなぐ:Webhook・HTTP Request・API