第 9 章

Item 是什麼?資料怎麼在節點間流動

n8n 最重要、也最容易被略過的觀念就一個字:item。搞懂 item 之後,「為什麼我的 workflow 只跑一次不是五次」「為什麼 Slack 節點傳了 100 遍」「為什麼 Expression 顯示 undefined」都會變合理。這章一次講清楚,之後每一章都會回來用。

為什麼要搞懂 item

第 8 章做完那個「早上把行事曆推 Slack」的 workflow 之後,你大概會發現幾件怪事:

  • Google Calendar 節點跑一次讀回五個事件,Slack 節點就自己傳了五次訊息——沒人叫它 for-loop 啊?
  • Expression 面板打 {{ $json.summary }} 明明有值,換成 {{ $json.items[0].summary }} 就 undefined。
  • Google Sheet 讀回一個空表,下游全部節點直接被跳過——連錯誤都沒噴,就是不跑。
  • 用 Set 節點加了一個欄位,結果 output 面板一次跑出五列,不是預期的一列。

這些現象背後都是同一件事:n8n 節點跟節點之間傳的不是一團 JSON,是一「列」一「列」的 item。跟 Zapier 把這件事藏起來不同,n8n 把 item 直接攤在你眼前——這也是它比 Zapier 強、但初學者比 Zapier 難的核心原因。

本章目標:讀完你會知道 item 是什麼、一個節點吃幾個 item、下一個節點會跑幾次、Expression 抓的到底是什麼、以及看 output 面板 debug 的正確姿勢。這章不用動手做新 workflow,但強烈建議打開第 8 章那個 workflow 一邊對照。

item 就是「一筆資料」,像 Excel 一列

最好用的比喻:每個節點的 output 就是一份 Excel 表格,表格的每一列就是一個 item。

Excel 用語n8n 用語實際長怎樣
一整份表格節點的 output(一個 array)[ {...}, {...}, {...} ]
一列一個 item{ name: "Elmo", age: 30 }
一欄item 裡的一個 fieldname、age
一格某個 item 的某個欄位值"Elmo"

然後最關鍵的規則:下一個節點會對「每一個 item」各跑一次。所以 Google Sheet 讀回 100 列 → Slack 節點就會傳 100 次訊息。這不是 bug,是 n8n 的核心行為,官方文件叫item-based execution。

提示:把「item = Excel 一列」這個比喻寫在便利貼貼螢幕上。之後每次看到 workflow 行為怪怪的,先問自己「這個節點的 input 有幾個 item?」,八成問題就找到了。

一個 item 內部有哪些「隔間」

一個 item 不是純 JSON,而是有幾個固定隔間的物件。你 99% 只會用第一個,但另外兩個知道存在會少踩坑。

隔間放什麼什麼時候會用到
json主要資料,一個純 JSON 物件。這是你 99% 時間在讀的地方。幾乎所有 workflow。
binary附加的檔案內容(PDF、圖片、CSV 等 binary data)。Gmail 附件、Google Drive 下載、API 回傳檔案。
pairedItem記錄「這個 item 是從上游哪個 item 來的」,用於 Merge 節點對齊。用 Merge 節點合流的時候。多數情況 n8n 自動填。

用程式碼看一個 item 完整長這樣:

{
  "json": {
    "name": "Elmo",
    "age": 30,
    "email": "[email protected]"
  },
  "binary": {
    "attachment": {
      "mimeType": "application/pdf",
      "fileName": "invoice.pdf",
      "data": "..."
    }
  },
  "pairedItem": { "item": 0 }
}

所以下一個節點要抓 name 這個欄位,路徑是 $json.name——注意是 $json.name 不是 $json.json.name,n8n 幫你把外面那層 json 拆掉了,讓 Expression 短一點。

在 Expression 裡抓資料的四個核心寫法

節點欄位切成 Expression 模式(欄位右上角那個齒輪或 = 標記)之後,就是進到 Expression 世界。抓 item 資料只有這四種寫法要背,其他都是變化:

寫法意思什麼時候用
{{ $json }}當前 item 的整包 JSON。想看整包長怎樣、傳給下游整包。
{{ $json.field }}當前 item 的某個欄位。最常用,例:{{ $json.summary }}、{{ $json.email }}。
{{ $json['field with space'] }}欄位名有空格或中文用中括號寫。API 回來的欄位叫 User Name、訂單編號時。
{{ $('Google Sheets').item.json.field }}抓上游指定節點的資料(不是上一個節點)。跳過中間節點抓兩三站前的資料。

$('節點名稱') 就是「用節點名找到上游那個節點的 output」的意思。節點名字是你在 canvas 上看到的那個(雙擊節點可以改)。這樣寫的好處是——就算中間插了一堆 Set / IF,你還是能直接回頭抓原始資料。

觀念:寫 Expression 的時候不用自己記語法。點欄位進 Expression 模式後,右邊會滑出「輸入」面板,左半邊列上游所有節點的資料(Table / JSON / Schema 三種檢視),你點哪個欄位它就幫你插入正確的 Expression。第 14 章會完整拆這個面板。

同一個節點會跑幾次?兩種模式

「這個節點會跑幾次」這件事,被兩個因素決定:input 有幾個 item 和 節點的 Execute Once 設定。多數內建節點的預設行為是「input 有幾個 item 就跑幾次」,但這是可以改的。

模式行為誰是這樣
對每個 item 各跑一次(預設)Input 有 N 個 item → 節點會跑 N 次 → output 通常也是 N 個 item。大部分整合類節點(Slack、Gmail、HTTP Request 打 API 等)。
吃全部 item 一次處理完Input 有 N 個 item → 節點只跑一次拿到整份 array → 你在裡面決定要 output 幾個。Set、Aggregate、Item Lists、Code node(可切)、Sub-workflow(可切)。

要看/改一個節點是哪一種:點節點打開設定 → 頂端切到 Settings 分頁 → 找 Execute Once 這個 toggle。開啟後這個節點無論 input 幾個 item,都只用第一個 item 跑一次,其他丟掉。

注意:Execute Once 是「用第一個 item 跑一次」,不是「把全部 item 整成一包跑一次」。這兩件事很多人搞混。真的要「把 5 個 item 合成 1 個包」,你需要的是 Aggregate 或 Item Lists 節點(第 16 章詳講)。

三個節點的資料流動實例

看抽象概念看到頭暈?拿最簡單的 3 節點 workflow 走一次就懂了:Manual Trigger → Google Sheets (Read) → Slack (Send)。假設 Google Sheet 裡有 5 列聯絡人。

階段節點Input items做什麼Output items
開頭Manual Trigger—(沒有 input)手動按 Execute 觸發。1 個空 item:[ {} ]
中間Google Sheets (Read Rows)1 個 item對這 1 個 item 跑一次,去 Sheet 讀回 5 列。5 個 items:[{row1}, {row2}, ...]
結尾Slack (Send Message)5 個 items對每個 item 跑一次 send → 傳 5 次訊息。5 個 items(每次 send 的結果)

看出來重點了嗎——資料筆數是被中間那個節點放大的。Manual Trigger 只丟 1 個空 item 進去,Google Sheets 把它「展開」成 5 個 items,Slack 就自動被連跑 5 次。整個流程沒有一行 for-loop 程式碼,全靠 item 觀念自動展開。

AI×Odoo stage1 workflow:14 個節點串成的資料流,示範 item 一路被展開、過濾、聚合
圖 9-1真實的 14 節點 workflow:資料從左邊的 Trigger 進來,一路被讀取、過濾、AI 分類、寫回 Odoo——每一條線傳的都是 items 陣列。
提示:大部分 Trigger 節點(Manual、Schedule)第一次啟動時只吐 1 個 item。真正把資料量放大的是之後的讀取節點(Google Sheets Read、Gmail Trigger 抓新信、資料庫 SELECT)。所以看 workflow 資料筆數對不對,看的是「哪個節點是資料來源」,不是看 Trigger。

看 output 面板讀 item 的三種檢視

節點按 Execute step(單獨跑這個節點)或整個 workflow 跑完之後,畫面右邊的 output 面板會顯示這個節點吐出的 items。頂端有三個檢視模式可以切,各有各的場合:

檢視看起來像什麼時候用
Table(表格)Excel 表格,欄位是 column、item 是 row。快速看每個 item 的值、比對筆數對不對。這是預設檢視。
JSON原始 JSON 陣列,可以展開/收合物件。Table 顯示不下(欄位太多/巢狀結構)、要複製整包貼到別的地方。
Schema樹狀的欄位結構圖,只顯示欄位名與型別,不顯示值。寫 Expression 前必看——知道有哪些欄位可以抓、路徑怎麼寫。

面板頂端還會顯示「N items」那個數字——這是你 debug 最常看的一個數字。跟你預期不一樣就代表這個節點出事了,往上游追。

Table 檢視每一列前面有個小數字(0、1、2...)就是 item index。抓「第一個 item 的某個欄位」就是 $json.field(當前那一次 iteration 的 item);不是 $json[0].field——這是初學者最常犯的錯之一。

觀念:Schema 檢視在 n8n 的重要性被嚴重低估。寫 Expression 前先切 Schema 看一下,能省掉九成「打了半天發現欄位名寫錯」的時間。Schema 上直接點欄位還會幫你把 Expression 插入到當前正在編輯的欄位。

為什麼我的 workflow 只跑 1 次不是 5 次?

這是新手第一週最常問的問題。原因永遠是三個之一,用Executions 逐節點看 item 數量就能定位:

原因症狀怎麼確認
A:Trigger 只吐 1 個 itemSchedule Trigger、Manual Trigger 預設每次觸發都只丟 1 個空 item。你以為它會「自動連跑 5 次」是誤解。Trigger 節點的 output 面板看 items 數量。
B:某節點被設 Execute Once上游有 5 個 items,這個節點只跑 1 次就結束——很可能是你或別人不小心開了 Settings → Execute Once。逐節點看 output items 數量,找那個「從 5 變 1」的節點。
C:Expression 抓錯層級你以為 $json.items 是把 items 展開,但其實它只是抓「當前 item 裡叫 items 的欄位」——那個欄位是個陣列,不是 n8n 的 items 概念。Schema 檢視看該節點 output 結構,判斷 items 是真的多個 item 還是一個 item 裡面有個叫 items 的陣列。

C 這個很坑:「n8n 的 items」跟「JSON 裡剛好叫 items 的欄位」是兩件事。API 常常回傳長這樣:

{
  "total": 5,
  "items": [
    { "id": 1, "name": "A" },
    { "id": 2, "name": "B" },
    ...
  ]
}

整包被 n8n 當成一個 item(因為 API 回傳就是一包)。要把 items 陣列展開成 5 個 n8n items,需要用 Split Out 節點(第 16 章)指定 items 這個欄位。展開後才會變成 5 個 item,下游節點才會被連跑 5 次。

binary data 什麼時候會用到

多數業務類 workflow 完全不會碰到 binary。只有涉及「檔案本身」的節點才會產生 binary:

  • Gmail Trigger 抓到有附件的信 → 附件在 binary.attachment_0、binary.attachment_1...
  • Google Drive Download → 檔案內容在 binary.data。
  • HTTP Request 收到 PDF/圖片回應,且 Response Format 選 File → binary。
  • Read/Write Binary File(self-host 才有意義)。

看 binary 要切到 output 面板的 Binary 分頁(跟 Table / JSON / Schema 平行的第四個分頁,有 binary 才會出現)。裡面會列每個 binary 的 mime type、檔名、大小,圖片還可以預覽。

注意:binary 直接塞在記憶體裡跟著整個 execution 一起跑,一個 10MB 附件 × 100 個 item 就是 1GB。碰到大檔案 workflow 有兩個原則:(1)能早處理完丟掉就早丟——用 Set 節點只留 $json、把 $binary 清掉;(2)避免不必要的 Execute Workflow 傳遞(sub-workflow 會複製一份)。

常見卡關

  1. Expression 顯示 undefined

    兩個可能:(1)欄位名打錯——切 Schema 檢視看真實欄位名(大小寫、有沒有空格、有沒有前綴 data.)。(2)上游節點根本沒跑成功——那個節點的 output 面板是空的或紅色。先修上游再管 Expression。

  2. 節點跑 100 次但你只想跑 1 次

    上游有 100 個 items 的緣故。三個做法選一個:(a)在中間插 Aggregate 節點把 100 個聚合成 1 個;(b)用 Code node(第 20 章)寫 return [ { json: { all: $input.all() } } ];(c)如果只想拿第一筆,該節點 Settings 開 Execute Once——但注意這是「只拿第一筆」不是「合併全部」。

  3. Merge 節點吐出來筆數對不上

    Merge 有四個 mode,選錯結果差很多:Append(頭接尾,A 3 個+B 2 個=5 個)、Combine(再切三個子選項:Matching Fields 靠欄位值比對像 SQL join、Position 同 index 湊一對、All Possible Combinations 笛卡兒積 A 3 個×B 2 個=6 個)、SQL Query(1.49.0+,直接寫 SQL 湊)、Choose Branch(只挑一邊的資料吐出)。舊版文件把 All Possible Combinations 叫 Multiplex,新版已經改名,看到別人 workflow 用舊稱不用慌。用之前先想清楚要哪一種,第 16 章會拆更細。

  4. 節點吃到 0 個 item 直接被跳過

    n8n 的行為:input 是空 array 時,節點不會跑。這是刻意的(不用寫 empty check)但初學者會誤以為節點壞了。往上游追是誰吐了 0 個——通常是(a)IF 節點兩個分支都沒過、(b)Google Sheet Read 沒讀到資料、(c)過濾節點把全部濾掉。

  5. Set 節點跑完 item 數量不對

    Set 節點預設對每個 item 各跑一次(保持 item 數量不變),這是對的。如果你發現 5 進 5 出但欄位跑掉,通常是 Set 的模式選了「Keep Only Set」把原欄位砍光了——改成「Include All Fields」或「Include Selected Fields」試試。第 18 章會完整拆 Set 節點。

  6. Expression 顯示的預覽跟實際跑出來不一樣

    Expression 編輯器預覽用的是「上游節點上一次跑的 output」——如果上游還沒跑或跑錯了,預覽就是舊值。解法:對上游節點按 Execute step 跑一次讓它產生新 output,再回來看 Expression 預覽。

常見問題

Zapier 也有這個 item 觀念嗎?
有,但 Zapier 把它藏起來了——Zapier 每個 Zap 每次觸發預設就是「一筆資料」,需要多筆時要另外開 Sub-Zap 或 loop by Zapier。n8n 選擇把 item 直接攤在你面前,好處是超彈性(同一個 workflow 可以處理 1 筆也可以處理 1000 筆),代價是初學者要多花 30 分鐘理解這個章節。理解之後你會覺得 Zapier 那種黑箱反而礙事。
一次能吃多少 item?有上限嗎?
技術上沒硬性上限,但實務有:n8n 是把整個 execution 的 items 放記憶體裡跑,幾千筆純 JSON 沒問題,上萬筆就會慢,帶 binary 的一兩百筆就可能撐爆。真的要處理大量資料,用 Split In Batches 節點分批跑(第 16 章),或者把資料處理拆到資料庫層做完再讓 n8n 只碰結果。
binary 資料會佔記憶體嗎?
會,而且吃很兇。一個 10MB 的 PDF 附件會完整塞在 execution 記憶體,如果又觸發 sub-workflow 還會被複製一份。原則:(1)不需要 binary 的 item 用 Set 節點清掉 binary;(2)Cloud 版有 execution size 上限,超過會失敗;(3)self-host 記得監控 n8n 容器記憶體用量。
怎麼看到 workflow 實際跑了多久、每個節點花多久?
側欄 Executions 頁面每一筆紀錄有總 duration。點進去可以看每個節點分別跑了多久(節點右上角的小時鐘標記)。慢的節點通常是打外部 API 的那幾個(Slack、Google 系列、HTTP Request),不是 n8n 自己慢。第 17 章錯誤處理會教怎麼設 timeout 跟 retry。
可以只讓 workflow 對「某幾個 item」跑而不是全部嗎?
可以。中間插一個 IF 或 Filter 節點做條件過濾,只有符合條件的 item 會往下走,其他被截住。或者用 Split In Batches 分批處理(例:一次 10 筆,跑 10 輪)。這些都會在第 16 章詳細講。
$json 跟 $input.all() 差在哪?
在一般節點的 Expression 欄位裡,$json 是「當前這一輪 iteration 的那個 item 的 json」——因為節點被連跑 N 次,每次的 $json 都指不同的 item。$input.all() 拿的是「這一個節點吃到的全部 items 的 array」(回傳 Array,各成員是完整 item,含 .json / .binary)。Expression 也能呼叫,但實務上最常在 Code node(第 20 章)用——因為 Code node 通常設成一次處理全部。相關姊妹:$input.first()、$input.last()、$input.item。