第 16 章

Merge / Loop Over Items / Split Out / Aggregate:處理多筆資料

上一章 IF / Switch 講的是分岔——一條路走成兩條。這章反過來:把兩條合成一條、把一次跑 500 筆改成一次跑 5 筆、把 API 回來的一大包陣列拆開變多筆。這些節點是 n8n 的水管工,每個實戰 workflow 幾乎都用得上。用語提醒:本章沿用官方最新命名,舊版的 Split In Batches 已改名為 Loop Over Items(節點介面顯示為「Loop Over Items (Split in Batches)」),舊版的 Item Lists 已拆成獨立節點 Split Out、Aggregate、Sort、Limit、Remove Duplicates、Summarize——搜尋節點時記得用新名字。

為什麼要學這三個節點

做過幾個 workflow 之後你一定會撞到下面這幾種情境:

  • IF 分完了不知道怎麼合回來。 IF 節點把資料拆成 true / false 兩條路,各自處理完之後想再一起發個總結通知——結果兩條路各跑各的,怎麼收都不對。
  • Airtable / Notion API 一秒 5 次上限,你一次餵 500 筆。 全部塞下去節點跑到一半就被 429 Too Many Requests 打回來,前面的成功了,後面的沒跑,很難補。
  • API 回來一個 item 裡有個 results 陣列,下游拿不到。 你在 第 9 章看過這個坑——{ total: 5, items: [...] } 整包被當成 1 個 item,下游 Slack 只傳 1 次不是 5 次。
  • 兩個 API 各回一半資料,要 join 才完整。 一邊是客戶基本資料、一邊是訂單金額,同一個 customer_id,你要湊起來變一份 report。

這四個問題由這幾個節點解掉:Merge(合流)、Loop Over Items(前身 Split In Batches,分批處理)、Split Out(陣列拆多筆 item)與 Aggregate(多筆 item 合回陣列)——後兩個以前叫 Item Lists,現在是各自獨立的節點。學會這幾個,你的 workflow 從「只會做玩具」進化到「可以扛正式業務」。

本章目標:讀完你能分清楚各節點的職責、知道 Merge 四種模式(Append / Combine / SQL Query / Choose Branch)差在哪、會用 Loop Over Items 配 Wait 節點避開 rate limit、會用 Split Out 把陣列展開成多個 item、會用 Aggregate 把多筆 item 收成一份 summary。動手範例會做兩個小 workflow,都能直接抄改自用。

節點分工一張表看完

先把幾個節點各自的位子擺清楚,之後看到情境就知道要挑哪一個:

節點解決什麼InputOutput經典場景
Merge 把兩條分支合成一條,或依 key join。 兩個(Input 1 / Input 2) 一條 items 陣列 IF 分岔處理完要合回來繼續、兩個 API 資料 join。
Loop Over Items
(前身 Split In Batches)
把一次 N 筆改成一輪 M 筆分幾輪跑。 一個(大量 items) 兩個:loop(本輪要處理)/done(全部跑完) API rate limit、記憶體吃不下、想加進度條分批通知。
Split Out
(前 Item Lists · Split Out Items)
把 item 裡的陣列欄位展開成多筆 item。 一個 多筆(陣列展平) API 回 { items: [...] }、Gmail 附件陣列。
Aggregate
(前 Item Lists · Aggregate Items)
多筆 item 合成單一 item 內的陣列。 多筆 一個 報表聚合、只寄一封 daily summary。
Sort / Limit / Remove Duplicates / Summarize 排序 / 取前 N / 去重 / 統計。 多筆 多筆或一個 舊 Item Lists 的其他操作,現在各自獨立節點。
提示:如果你會 SQL:Merge 的 Combine → Matching Fields 就是 JOIN、Merge Append 就是 UNION ALL、Split Out 就是 UNNEST、Aggregate 就是 GROUP BY 收成 array、Summarize 是 GROUP BY 配聚合函數。名字換而已,心智模型一樣。

Merge 節點:Mode 有四種,Combine 底下再三選一

Merge 節點一定要有兩個 input(拖線的時候會看到兩個接點)。Mode 這個下拉有四個選項——是官方 2024 年之後改過的結構,跟舊教學文常見的「三種模式」不同:

Mode做什麼備註
Append Keep data from all inputs:把兩邊 items 依序上下疊起來。 Input 1 = 3 筆、Input 2 = 2 筆,output = 5 筆。像 Excel 上下貼。
Combine Combine data from two inputs:把兩邊欄位左右拼起來,底下再選 Combine By 三選一(見下表)。 這是最常用的合併模式,取代舊版直接列出的 Combine by Position / by Key / Multiplex。
SQL Query 寫一段 SQL(SELECT ... FROM input1 JOIN input2 ...)自定義合併規則。 複雜 JOIN、複雜 WHERE 用得到,UI 拉不出來的都寫這裡。
Choose Branch 只保留其中一邊:像「兩條分支中挑一條的資料繼續往下」。 不是合併,是二選一。取代早期用兩個 IF 湊出來的寫法。

選了 Combine 之後 Combine By 底下的三個策略:

Combine By做什麼Input 1Input 2Output
Matching Fields Compare items by field values:以 key 值配對,等於 SQL JOIN。 客戶資料(用 id) 訂單資料(用 customer_id) 依 Output Type 決定要不要留沒 match 的
Position Combine items based on their order:以陣列位置對齊拼欄位。 [{a:1},{a:2},{a:3}] [{b:x},{b:y},{b:z}] [{a:1,b:x},{a:2,b:y},{a:3,b:z}]
All Possible Combinations Output all possible item combinations:笛卡兒積(cross join / multiplex)。 3 筆 2 筆 3 × 2 = 6 筆

選 Matching Fields 時 Output Type 決定 join 種類(官方五個都給齊):

  • Keep Matches —— 兩邊都有匹配才 output(inner join)。
  • Keep Non-Matches —— 沒配對到才 output(找差集用,例:「哪些客戶沒下過單」)。
  • Keep Everything —— 全部保留,沒配對到的欄位是 null(full outer join)。
  • Enrich Input 1 —— 以 Input 1 為主,把 Input 2 對得起來的欄位貼上(left join)。
  • Enrich Input 2 —— 以 Input 2 為主,把 Input 1 對得起來的欄位貼上(right join)。
觀念:Merge 節點兩個 input 都要有東西進去節點才會跑。所以做 IF 分岔的合流時,兩條路都要接到 Merge 的兩個 input。如果一條路是「什麼都不做」,也要串一個 No Operation, do nothing 節點再進 Merge,不然 Merge 會等到永遠。

Loop Over Items(前身 Split In Batches):分批處理避開 rate limit

情境:Airtable 官方 API 每秒最多 5 個 request,你的 Google Sheet 有 500 列客戶要寫進 Airtable。直接拉線一次餵,跑到第 5 筆之後就會開始收 429,剩下 495 筆全掛。這時候 Loop Over Items 上場。

命名一次講清楚:這個節點以前叫 Split In Batches,官方 2024 年之後在編輯器裡顯示為 Loop Over Items (Split in Batches)——搜尋 Loop、Split、batches 三個關鍵字都能找到,用起來完全一樣。舊 workflow JSON 裡的 splitInBatches type 相容不用改。

它的行為有點特別,第一次看會困惑——它是自己形成 loop 的節點。

設定 / 欄位做什麼常見值
Batch Size一輪吐幾個 items 到 loop output。Airtable 抓 5、一般 API 抓 10~50。
Options → Reset是否在有新 items 進來時重置計數器。單次 workflow 通常保持關;持續呼叫要開。
Output: loop這一批要處理的 items(下游接處理節點)。接 Airtable / HTTP Request。
Output: done全部跑完之後才會走這條,只跑一次。接「全部完成」的通知或彙總。

畫在 canvas 上會長成這樣(loop 那邊的節點跑完要拉線回來接回 Loop Over Items 節點,形成迴圈):

Google Sheets (500 items)
  ↓
Loop Over Items (Batch Size = 5)
  ├─ loop → Airtable Create → Wait 1 second ──┐
  │                                            │
  │←──────────── 回接 Loop Over Items 節點 ────┘
  │
  └─ done → Slack "500 筆處理完了"
注意:Wait 節點是搭配神器。API 每秒 5 次,Batch Size 設 5,Wait 設 1 秒,就是穩穩貼著 rate limit 跑。不加 Wait 節點雖然分批了,但每一批之間沒有停頓,5×N 次 request 幾乎瞬間送完,還是會炸。

Loop Over Items 本身不會產生「進度條」訊息,但每一輪 loop 都會經過同一批節點——想在半路報進度,就在 loop 分支上加個 Slack 節點傳「第 N 批處理完,還剩 M 批」。

Split Out / Aggregate:把陣列展平、把 items 收成陣列

命名一次講清楚:過去 n8n 有個「Item Lists」節點,一個節點內含 Split Out Items / Aggregate Items / Sort / Limit / Remove Duplicates / Summarize 六個 operation。現在官方已把它拆成六個獨立節點,各自叫 Split Out、Aggregate、Sort、Limit、Remove Duplicates、Summarize。搜尋節點時直接輸入新名字就好;舊 workflow 匯入還是可以跑,但新版 UI 已看不到 Item Lists。

Split Out:一個 item 內的陣列 → 多個 items

經典場景:Gmail 節點收到一封信,binary 或 json 裡有個 attachments 陣列,有 5 個附件。整包被當成 1 個 item,你想對「每個附件」跑一次上傳到 Google Drive。

設定值意義
Fields To Split Outattachments(或該陣列的路徑,逗號分隔可多個)指定要拆的陣列在哪個欄位。
IncludeNo Other Fields / All Other Fields / Selected Other Fields拆出來的每筆 item 要不要帶原本 item 的其他欄位(例:郵件主旨)。
Options → Destination Field Name可留空,或指定新欄位名拆出來的每筆內容要放到哪個 key 底下。留空就是打平。
Options → Disable Dot Notation預設關欄位名本身就含 . 時要開,避免被誤解成巢狀路徑。

拆完 output 從 1 個 item 變成 5 個 items,下游每個節點自動被跑 5 次。這就是第 9 章裡那個「n8n 的 items 跟 JSON 裡叫 items 的欄位是兩件事」的解法——用 Split Out 把 JSON 陣列變成 n8n items。

Aggregate:多個 items → 合成一個 item 內的陣列

反過來的操作。5 個 items 處理完,你想合成一份 daily summary 只發一次 email。加入 Aggregate 節點,Aggregate 選項二選一:

  • Individual Fields —— 只聚合指定的幾個欄位,可設 Rename Field 換名字,並可開 Merge Lists 把子陣列打平。
  • All Item Data (Into a Single List) —— 把每個 item 的完整 json 塞成一個大 array,可指定 Include / Exclude 白名單黑名單。

另外 Sort(排序,SQL ORDER BY)、Limit(取前 N 筆,SQL LIMIT)、Remove Duplicates(去重,SQL DISTINCT)、Summarize(分組統計,SQL GROUP BY + 聚合函數)現在也是各自獨立的節點——需要哪個就搜尋哪個。

實例:Google Sheet 每一列都發一則 Slack 提醒

這個 workflow 展示的是「item 天然被展開,根本不用 Loop Over Items」——因為 Google Sheets Read 本身就是把每一列變一個 item。當作暖身。

  1. 加 Manual Trigger

    新增 workflow,第一個節點選 Trigger manually。這樣按 Execute Workflow 就會跑一次。

  2. 加 Google Sheets 節點

    接一個 Google Sheets 節點,Operation 選 Get Rows in Sheet。連好 credentials(第 2 章),選你的試算表跟工作表。假設試算表叫「客戶名單」,有 10 列,欄位是 name、email、due_date。

  3. Execute step 確認吃到 10 個 items

    對 Google Sheets 節點按 Execute step。右邊 output 面板頂端會顯示 10 items——確認筆數對。切 Table 檢視看每列內容。

  4. 加 Slack 節點

    接一個 Slack 節點,Operation 選 Send Message,選頻道(例:#billing-reminder)。Text 欄位切 Expression 模式,輸入:

    {{ $json.name }} 的月結單提醒,到期日 {{ $json.due_date }},請盡快處理。
  5. 整個 workflow Execute 一次

    按右上 Execute Workflow。Slack 節點的 output 面板會顯示 10 items——代表傳了 10 次訊息,每一列各一則。頻道去確認實際收到 10 則。

  6. Save 存檔

    右上 Save。之後任何時候按 Execute Workflow 都會重新發一輪。要排程每月 1 號自動發,把 Manual Trigger 換成 Schedule Trigger(第 10 章)。

提示:這個範例整個沒用到本章任何節點——因為 Google Sheets Read 天然就把 10 列變 10 個 items 了。「天然多筆」跟「陣列裡多筆」是兩件事,下一個範例就是後者。

實例:API 回一包陣列,拆開對每一筆做事

這才是 Split Out 的主場。我們打一個公開 API(例:https://jsonplaceholder.typicode.com/users),它會回 10 個使用者的一整包陣列——n8n 收到的是 1 個 item,欄位是陣列。要對每個使用者發 Slack 通知,就要 Split Out。

  1. Manual Trigger + HTTP Request

    Trigger 選 Manual。接 HTTP Request 節點,Method 選 GET,URL 填 https://jsonplaceholder.typicode.com/users。Execute step 跑一次。

  2. 看 output 確認是 1 個 item 裡有陣列

    Output 面板頂端會顯示 1 item(不是 10)。切 JSON 檢視展開,會看到整個回應是個 array。這時下游任何節點只會跑 1 次——不對,我們要跑 10 次。

  3. 加 Split Out 節點

    接一個 Split Out 節點(搜尋「split out」直接找到,舊教學文的「Item Lists → Split Out Items」現在就是這個獨立節點)。Fields To Split Out 填該陣列所在的欄位——如果 HTTP Request 直接把整個陣列放在 data 或根層,就用對應路徑(實測時看 output 面板實際路徑填)。

  4. Execute step 確認變成 10 個 items

    對 Split Out 節點按 Execute step。Output 面板頂端顯示 10 items——每個使用者一列。切 Table 檢視看 name、email 都有值。

  5. 接 Slack 節點對每筆通知

    接 Slack 節點 Send Message,Text 用 歡迎 {{ $json.name }}({{ $json.email }})。Execute Workflow 跑一次 → Slack 頻道會收到 10 則歡迎訊息。

  6. (進階)Aggregate 合回一份總結

    在 Slack 節點後面再加一個 Aggregate 節點,Aggregate 選 Individual Fields,Field To Aggregate 選 name(可 Rename 成 names)。Output 變回 1 個 item,欄位是 10 個名字的陣列。再接 Gmail 節點寄「今天處理了這 10 位使用者:{{ $json.names.join('、') }}」——只寄 1 封 summary,不會被 10 個提醒淹沒信箱。

注意:Fields To Split Out 一定要填「陣列本身的欄位路徑」,不是陣列裡面某個欄位。填錯是最常見的坑——output 會跟 input 一樣是 1 個 item,看起來像節點沒動作。切 Schema 檢視上游看清楚路徑再填。

四種常見組合技

單一節點會用只是入門,真正的力量在於「兩三個湊在一起」。這幾個組合幾乎每週都會用到:

組合解決什麼結構
IF + Merge 分岔各自處理不同事,再合回一條 continue 下游。 IF → true 分支 (Set A) & false 分支 (Set B) → Merge (Append) → Slack
Loop Over Items + Wait 分批處理配停頓避開 rate limit。 Loop Over Items → HTTP Request → Wait 1s → 回接 Loop Over Items
Split Out + 處理 + Aggregate API 一大包陣列 → 對每筆各做事 → 合成一份 summary。 HTTP Request → Split Out → 處理節點 → Aggregate → Email
Merge Combine · Matching Fields 兩個資料來源用 key join 成完整資料。 HTTP A →     ↓
HTTP B → Merge (Mode = Combine, Combine By = Matching Fields, id ↔ customer_id) → 下游

這些組合都適合先在第 8 章那個練習 workflow 上加加改改,先跑通再套到正式業務。

AI×Odoo 多分支 workflow 含 Merge 合流節點
圖 16-1實戰範例:AI×Odoo 14 節點 workflow,多條分支跑完後用 Merge 合流回主線繼續下游處理。

常見卡關

  1. Merge Combine · Position 少了一半資料

    Combine By = Position 是「以位置對齊」——Input 1 有 3 個、Input 2 有 5 個,output 只會有 3 個(以短的為準),後面 2 個直接被丟掉。要保留全部改用 Combine By = Matching Fields 配 Output Type Keep Everything,或改用 Append mode 上下貼再處理。

  2. Loop Over Items 停不下來、無限跑

    兩個常見原因:(a)loop 分支的節點沒接回 Loop Over Items 節點——loop 只跑一輪,後面資料被丟掉,但整體不會炸;如果反過來接錯線接到 done 分支就會奇怪;(b)Options → Reset 開了,而上游一直有新 items 進來(例:Webhook 觸發),每次都當作新一輪。除非做長駐服務不然關掉。

  3. Split Out 拆完 output 一模一樣

    八成是 Fields To Split Out 填錯:(a)欄位名打錯(大小寫、單複數);(b)填了陣列裡的某個欄位而不是陣列本身;(c)該欄位根本不是陣列而是物件。切 Schema 檢視上游節點,找型別是 array 的那個欄位,把完整路徑(例:data.results)貼進來。

  4. Merge 完 items 順序跑掉

    不同 mode 的順序規則不一樣:Append 保證 Input 1 全部在前、Input 2 全部在後;Combine · Position 保證同 index 對齊;Combine · Matching Fields 順序依 Input 1 的 key 出現順序——你想要特定順序,用 Sort 節點在 Merge 前後排一下。

  5. Merge 節點卡住不執行

    Merge 一定要兩個 input 都有資料才會跑。IF 分岔時如果 true 分支沒有任何 item 走過去(條件全部 false),Merge 會等到永遠。解法:在空分支上串個 No Operation, do nothing 節點(不改資料只轉線)或用 IF 節點的 Fallback Output 保證兩邊都有東西進 Merge。

  6. Loop Over Items 配 Wait 但 Wait 時間沒被遵守

    Wait 節點的秒數是「這個 item 到這裡等 N 秒才走」——Batch Size = 5 表示同一批 5 個 items 幾乎同時抵達 Wait,然後各自等 5 秒(不是這一批等 1 次 5 秒)。想要「每批間隔 5 秒」,Batch Size 保持 5、Wait 設 5,實測看清楚實際 request 送出的時間戳。

常見問題

Merge 節點一定要兩個 input 嗎,可以三個以上嗎?
預設是兩個。想合三個以上,最直接的做法是串接兩個 Merge——A、B 先進第一個 Merge,output 再跟 C 進第二個 Merge,以此類推。Merge 節點本身不支援直接三個以上的 input 接口。
Loop Over Items 一次能設多大 Batch Size?
技術上沒硬性上限,實務上建議 10~50 起跳,最多不超過 500。太小(例:1)節點被跑幾百輪整個 workflow 慢;太大(例:5000)失去分批意義而且吃記憶體。準則:剛好貼著下游 API 的 rate limit 或 batch API 的一批上限。Airtable batch endpoint 一次最多 10 筆,Batch Size 就設 10。
Split Out 跟 Code node 拆陣列,哪個好?
純粹「把某欄位的陣列展開成多筆」用 Split Out 就好,不用寫程式。要拆的過程需要條件判斷、轉型、過濾、算欄位,或者陣列結構很怪(陣列裡還有陣列)就用 Code node(第 20 章)。原則:能不寫程式就不寫,內建節點永遠優先。
n8n workflow 有多執行緒嗎,能同時處理多筆嗎?
單一 workflow execution 內部是循序處理 items——一個節點對 100 個 items 是「跑 100 次」不是「同時 100 個 thread」。想要「不要等前一筆跑完」的並行效果,兩條路:(a)用 Loop Over Items 把工作切小塊分開跑;(b)self-host n8n 開多個 worker(EXECUTIONS_MODE=queue)讓多個 workflow execution 同時跑。單一 execution 內部的並行不是 n8n 的設計方向。
如果我只想在 500 筆裡處理前 10 筆試看看,怎麼做?
最簡單:在資料源後面接一個 Limit 節點(前身是 Item Lists 的 Limit operation,現在獨立成節點),Max Items 設 10。上線前把 Limit 節點停用(節點右鍵 Deactivate)或直接刪掉。這是開發階段的好習慣,避免測試時真的 send 500 封 email 出去。
Merge Combine · Matching Fields 對得起來的規則是什麼?大小寫敏感嗎?
n8n 用嚴格相等比對(同型別同值才算 match)。字串大小寫敏感——"Alice" 跟 "alice" 不會 match。型別敏感——字串 "123" 跟數字 123 也不會 match。碰到型別不一致,先用 Set 節點統一型別(轉字串或轉數字)再進 Merge;或用 Merge 的 SQL Query mode 寫 CAST。
Loop Over Items 跑到一半失敗會怎樣,前面已處理的資料會回滾嗎?
不會回滾——n8n 沒有 transaction 概念。已經寫進 Airtable / Slack 的資料就是寫進去了,第 N 批失敗只影響 N 之後。做法:(a)在 loop 分支加 Error Trigger / continueOnFail(第 17 章),單筆失敗只 log 不中斷;(b)處理前先 dedupe,這樣重跑不會產生重複資料。
Merge 的 SQL Query mode 什麼時候該用?
當 UI 的 Combine By 三個策略滿足不了需求就開 SQL Query,例如:多欄位條件 join(ON a.id = b.customer_id AND a.region = b.region)、需要 CASE WHEN、需要 UNION 加 WHERE 篩選、需要 subquery。n8n 在背後用 alasql 執行,兩個 input 對應資料表 input1 / input2。單純 append / 位置對齊 / 單欄位 join 就用普通 mode,不用刻意搬到 SQL。
Aggregate 完的陣列在 Expression 裡怎麼用?
跟一般陣列一樣。假設 Aggregate 把 name 聚合到 names,下游 Expression 可以寫 {{ $json.names.join('、') }}(用頓號串成一行字)、{{ $json.names.length }}(幾筆)、{{ $json.names.filter(n => n.startsWith('王')) }}(篩選)。這些寫法在 第 14 章 Expressions 有完整清單。