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 從「只會做玩具」進化到「可以扛正式業務」。
節點分工一張表看完
先把幾個節點各自的位子擺清楚,之後看到情境就知道要挑哪一個:
| 節點 | 解決什麼 | Input | Output | 經典場景 |
|---|---|---|---|---|
| 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 的其他操作,現在各自獨立節點。 |
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 1 | Input 2 | Output |
|---|---|---|---|---|
| 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)。
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 筆處理完了"
Loop Over Items 本身不會產生「進度條」訊息,但每一輪 loop 都會經過同一批節點——想在半路報進度,就在 loop 分支上加個 Slack 節點傳「第 N 批處理完,還剩 M 批」。
Split Out / Aggregate:把陣列展平、把 items 收成陣列
Split Out:一個 item 內的陣列 → 多個 items
經典場景:Gmail 節點收到一封信,binary 或 json 裡有個 attachments 陣列,有 5 個附件。整包被當成 1 個 item,你想對「每個附件」跑一次上傳到 Google Drive。
| 設定 | 值 | 意義 |
|---|---|---|
| Fields To Split Out | attachments(或該陣列的路徑,逗號分隔可多個) | 指定要拆的陣列在哪個欄位。 |
| Include | No 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。當作暖身。
-
加 Manual Trigger
新增 workflow,第一個節點選 Trigger manually。這樣按 Execute Workflow 就會跑一次。
-
加 Google Sheets 節點
接一個 Google Sheets 節點,Operation 選 Get Rows in Sheet。連好 credentials(第 2 章),選你的試算表跟工作表。假設試算表叫「客戶名單」,有 10 列,欄位是
name、email、due_date。 -
Execute step 確認吃到 10 個 items
對 Google Sheets 節點按 Execute step。右邊 output 面板頂端會顯示 10 items——確認筆數對。切 Table 檢視看每列內容。
-
加 Slack 節點
接一個 Slack 節點,Operation 選 Send Message,選頻道(例:
#billing-reminder)。Text 欄位切 Expression 模式,輸入:{{ $json.name }} 的月結單提醒,到期日 {{ $json.due_date }},請盡快處理。 -
整個 workflow Execute 一次
按右上 Execute Workflow。Slack 節點的 output 面板會顯示 10 items——代表傳了 10 次訊息,每一列各一則。頻道去確認實際收到 10 則。
-
Save 存檔
右上 Save。之後任何時候按 Execute Workflow 都會重新發一輪。要排程每月 1 號自動發,把 Manual Trigger 換成 Schedule Trigger(第 10 章)。
實例:API 回一包陣列,拆開對每一筆做事
這才是 Split Out 的主場。我們打一個公開 API(例:https://jsonplaceholder.typicode.com/users),它會回 10 個使用者的一整包陣列——n8n 收到的是 1 個 item,欄位是陣列。要對每個使用者發 Slack 通知,就要 Split Out。
-
Manual Trigger + HTTP Request
Trigger 選 Manual。接 HTTP Request 節點,Method 選 GET,URL 填
https://jsonplaceholder.typicode.com/users。Execute step 跑一次。 -
看 output 確認是 1 個 item 裡有陣列
Output 面板頂端會顯示 1 item(不是 10)。切 JSON 檢視展開,會看到整個回應是個 array。這時下游任何節點只會跑 1 次——不對,我們要跑 10 次。
-
加 Split Out 節點
接一個 Split Out 節點(搜尋「split out」直接找到,舊教學文的「Item Lists → Split Out Items」現在就是這個獨立節點)。Fields To Split Out 填該陣列所在的欄位——如果 HTTP Request 直接把整個陣列放在
data或根層,就用對應路徑(實測時看 output 面板實際路徑填)。 -
Execute step 確認變成 10 個 items
對 Split Out 節點按 Execute step。Output 面板頂端顯示 10 items——每個使用者一列。切 Table 檢視看
name、email都有值。 -
接 Slack 節點對每筆通知
接 Slack 節點 Send Message,Text 用
歡迎 {{ $json.name }}({{ $json.email }})。Execute Workflow 跑一次 → Slack 頻道會收到 10 則歡迎訊息。 -
(進階)Aggregate 合回一份總結
在 Slack 節點後面再加一個 Aggregate 節點,Aggregate 選 Individual Fields,Field To Aggregate 選
name(可 Rename 成names)。Output 變回 1 個 item,欄位是 10 個名字的陣列。再接 Gmail 節點寄「今天處理了這 10 位使用者:{{ $json.names.join('、') }}」——只寄 1 封 summary,不會被 10 個提醒淹沒信箱。
四種常見組合技
單一節點會用只是入門,真正的力量在於「兩三個湊在一起」。這幾個組合幾乎每週都會用到:
| 組合 | 解決什麼 | 結構 |
|---|---|---|
| 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 上加加改改,先跑通再套到正式業務。
常見卡關
-
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 上下貼再處理。
-
Loop Over Items 停不下來、無限跑
兩個常見原因:(a)loop 分支的節點沒接回 Loop Over Items 節點——loop 只跑一輪,後面資料被丟掉,但整體不會炸;如果反過來接錯線接到 done 分支就會奇怪;(b)Options → Reset 開了,而上游一直有新 items 進來(例:Webhook 觸發),每次都當作新一輪。除非做長駐服務不然關掉。
-
Split Out 拆完 output 一模一樣
八成是 Fields To Split Out 填錯:(a)欄位名打錯(大小寫、單複數);(b)填了陣列裡的某個欄位而不是陣列本身;(c)該欄位根本不是陣列而是物件。切 Schema 檢視上游節點,找型別是
array的那個欄位,把完整路徑(例:data.results)貼進來。 -
Merge 完 items 順序跑掉
不同 mode 的順序規則不一樣:Append 保證 Input 1 全部在前、Input 2 全部在後;Combine · Position 保證同 index 對齊;Combine · Matching Fields 順序依 Input 1 的 key 出現順序——你想要特定順序,用 Sort 節點在 Merge 前後排一下。
-
Merge 節點卡住不執行
Merge 一定要兩個 input 都有資料才會跑。IF 分岔時如果 true 分支沒有任何 item 走過去(條件全部 false),Merge 會等到永遠。解法:在空分支上串個 No Operation, do nothing 節點(不改資料只轉線)或用 IF 節點的 Fallback Output 保證兩邊都有東西進 Merge。
-
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 嗎,可以三個以上嗎?
Loop Over Items 一次能設多大 Batch Size?
Split Out 跟 Code node 拆陣列,哪個好?
n8n workflow 有多執行緒嗎,能同時處理多筆嗎?
EXECUTIONS_MODE=queue)讓多個 workflow execution 同時跑。單一 execution 內部的並行不是 n8n 的設計方向。如果我只想在 500 筆裡處理前 10 筆試看看,怎麼做?
Merge Combine · Matching Fields 對得起來的規則是什麼?大小寫敏感嗎?
"Alice" 跟 "alice" 不會 match。型別敏感——字串 "123" 跟數字 123 也不會 match。碰到型別不一致,先用 Set 節點統一型別(轉字串或轉數字)再進 Merge;或用 Merge 的 SQL Query mode 寫 CAST。Loop Over Items 跑到一半失敗會怎樣,前面已處理的資料會回滾嗎?
Merge 的 SQL Query mode 什麼時候該用?
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 裡怎麼用?
name 聚合到 names,下游 Expression 可以寫 {{ $json.names.join('、') }}(用頓號串成一行字)、{{ $json.names.length }}(幾筆)、{{ $json.names.filter(n => n.startsWith('王')) }}(篩選)。這些寫法在 第 14 章 Expressions 有完整清單。