第 18 章

Set / Edit Fields:資料整形不寫程式

上一個節點吐一大包 JSON,可是下一個節點只需要其中幾個欄位、或者要合併、要改名、要加預設值——這種「換一下形狀」的事,不用寫程式。Set 節點(新版介面叫 Edit Fields)就是專門做這件事的視覺化工具。這章把它玩透,你的 workflow 會少寫一大堆 Code。

為什麼需要「資料整形」這一步

你在 第 9 章學過 items 是 n8n 的基本流動單位,每個 item 都是一包 JSON。在 第 11 章串 SaaS 節點時,你八成已經碰到這個場景:

  • HTTP Request 節點吐回來:{ firstName: "小明", lastName: "王", email: "[email protected]", age: 28, avatar_url: "...", ... }
  • 可是下一個 Google Sheets 節點只要三個欄位:{ 姓名: "王小明", 信箱: "[email protected]", 年齡: 28 }

你不會想在 Sheets 節點裡寫十行 expression 硬拼,也不想動不動就開 Code 節點寫 JavaScript。你要的是一個「中間站」,把上游的 JSON 洗成下游想要的樣子——這就是 Set 節點。它不打 API、不觸發、不對外做任何事,純粹就是「把 JSON 換一個形狀」再吐出去。

觀念:Set 節點的定位是 workflow 裡的「梳妝台」——上游資料進來,梳一梳、化個妝、換個衣服,再送到下游。全部工作僅限於改 JSON 結構,不會產生副作用。

Set 節點到底在做什麼

把 Set 節點想成一台加工機。它的流程就三步:

  1. 讀 input items

    它會拿到上一個節點吐出來的所有 items(一包或多包 JSON)。跟其他節點一樣,n8n 會自動幫你對每一筆 item 執行一次。

  2. 依照你的設定重新組裝 JSON

    你在 Set 節點裡設「要留哪些欄位、要加哪些欄位、要改哪些欄位」,它照你的規則重新組出新的 JSON。

  3. 吐 output items

    整形好的 items 送給下一個節點。原本的 input 不受影響——Set 節點是「產出新版本」,不是「就地改 input」。

就這樣。沒 API call、沒 webhook、沒 side effect。它是 n8n 裡最快、最安全的節點之一,執行時間通常在毫秒等級。

提示:「Set」是 n8n 舊介面用的名字(含意:set the value of a field),新版介面把它改名叫 Edit Fields (Set)——意圖更白話。兩個是同一個節點,功能完全一樣,找節點時搜「set」或「edit fields」都找得到。

兩個工作模式:Manual Mapping vs JSON

Set 節點打開後,最上面有個 Mode 下拉,只有兩個選項:

模式怎麼設什麼時候用
Manual Mapping(預設) 一欄一欄按 Add Field 加:Name(新欄位叫什麼)+ Type(String / Number / Boolean / Array / Object)+ Value(用 expression 或固定值) 90% 的情況。加幾個欄位、改幾個欄位名、給幾個預設值——手動介面看得最清楚
JSON 直接貼一整段 JSON template,裡面用 {{ }} 插 expression 動態填值 要重新規劃 JSON 結構(例:把扁平資料變成巢狀)、或者你已經有一段 JSON 範本要照抄

兩個模式做的事情本質是一樣的——「產出一段新的 JSON」。差別只在你用視覺化介面設,還是自己貼 JSON 文字。新手一律從 Manual Mapping 開始,遇到需要巢狀結構時才切 JSON。

注意:兩個模式不能混用。切模式時你已經設好的內容不會自動轉換——切過去以後要重新設。所以一開始就想清楚要用哪個模式,比較不會白工。

動手做:把 firstName + lastName 合成 full_name

這是最典型的 Set 節點用途。假設上游節點吐出:

{
  "firstName": "小明",
  "lastName": "王",
  "email": "[email protected]",
  "age": 28
}

你想在後面多一個欄位叫 full_name,值是 王小明(台灣人姓在前)。跟著做:

  1. 加一個 Edit Fields 節點

    在畫布上按 + 加節點,搜 edit fields 或 set,選 Edit Fields (Set)。把它接在會吐出上面那包 JSON 的節點後面。

  2. Mode 保持 Manual Mapping

    預設就是 Manual Mapping,不用動。

  3. Fields to Set 按 Add Field

    下方會出現一組空白的欄位設定卡。Type 選 String(因為 full_name 是字串)。

  4. Name 填 full_name

    這是新欄位的名字,會出現在下游看到的 JSON 裡。

  5. Value 填 expression {{ $json.lastName }}{{ $json.firstName }}

    Value 欄位右上角有個 Expression 切換鈕,切到 Expression 模式後貼上這串。Expression 語法看 第 14 章——$json 就是「當前這一筆 item 的 JSON」。

  6. Include Other Input Fields 打勾

    節點下面有一個很重要的 toggle:Include Other Input Fields(v1 UI 實際字樣,官方 docs 頁還寫舊字 Keep Only Set Fields,邏輯是反的)。打勾=保留原本的所有欄位、再加上你設的 full_name。不打勾=只留你設的欄位(其他丟掉)。這裡打勾。

  7. Execute Node 看結果

    按節點右上的 Execute Node。Output 面板應該吐出:{ firstName: "小明", lastName: "王", email: "...", age: 28, full_name: "王小明" }——原本的欄位全在,多了一個 full_name。任務達成。

提示:Expression 欄位有藍色小燈泡,點開會列出上游所有可用欄位。不用背路徑,直接在燈泡列表裡點欄位名,n8n 會自動幫你插入正確的 {{ $json.xxx }}。

五種最常見的 Set 用法速查

把這五招學會,Set 節點的日常應用九成都涵蓋了。

要做什麼設定方式Value 範例
加一個新欄位(時間戳、狀態標記) Add Field,Name 填新欄位名,Value 用 expression 產值 {{ $now }} 產當前時間;已處理 純字串
改欄位名(rename) Add Field 新名字、Value 用 {{ $json.舊欄位 }} 引舊值;再把 Include Other Input Fields 關掉 或明列所有要留的欄位 Name = customer_email, Value = {{ $json.email }}
給預設值(欄位缺就填) Value 用三元運算子判斷有沒有值 {{ $json.phone || '未提供' }}
型別轉換(字串轉數字之類) 用 JavaScript 內建函式包一下 {{ Number($json.amount) }}、{{ String($json.id) }}、{{ Boolean($json.is_vip) }}
條件填值(依上游值決定填什麼) 用三元運算子(條件 ? A : B) {{ $json.amount > 1000 ? 'VIP' : '一般' }}

這五招都是 Manual Mapping 模式做得到的——不用開 Code 節點,不用寫函式。expression 裡能用的 JavaScript 內建函式(Number、String、Boolean、Math.round、Date、字串的 .toUpperCase()、.trim()、.split() 等)大多都能直接寫。

提示:Value 欄位除了打 expression,還可以拖曳——把左邊 input 面板的欄位直接拖到 Value 輸入框裡,n8n 會自動幫你貼上 {{ $json.xxx }}。新手用這招最省事。

Include Other Input Fields:新手最常踩雷的 toggle

這個 toggle 是 Set 節點最容易搞混的地方,值得單獨拎出來講。

Toggle 狀態行為Output 會有什麼
Include Other Input Fields 打勾 保留 input 原本所有欄位,你設的 fields 會覆蓋(同名)或加上(新名) 原本 5 個欄位 + 你新加的 2 個 = 7 個欄位
Include Other Input Fields 關掉 只留你在 Fields to Set 裡明列的欄位,其他全丟掉 你設 2 個欄位 = 只有 2 個欄位

什麼時候用什麼?

  • 加欄位、改欄位但想保留其他 → 打勾。這是最常見的用法。
  • 大清洗——只想留三個欄位丟給下游 → 關掉,然後在 Fields to Set 明列你要的三個欄位。
  • 安全考量——上游 API 回應裡有敏感欄位(token、password_hash),不想帶到下游 → 關掉,只挑安全的欄位放行。
注意:如果你關掉這個 toggle 但忘了在 Fields to Set 裡加 email,那你的下游節點就永遠拿不到 email——這是新手最常見的「欄位不見」bug。輸出面板看到欄位少了,第一個先檢查這個 toggle。另外一個常見誤解:這個 toggle 只保留「當前 input item」的欄位;如果你想引用更早前幾個節點的 payload,還是要用 {{ $('節點名').item.json.xxx }}(見 FAQ 最後一題)。

舊版介面這個 toggle 叫 Keep Only Set Fields(保留邏輯剛好相反:打勾=只留 set 的),v1 之後改叫 Include Other Input Fields(打勾=保留其他),語意直覺很多。注意 n8n 官方 docs 頁到今天仍寫舊字 Keep Only Set Fields,跟你在 UI 看到的字對不起來很正常;以 UI 字樣為準。

JSON 模式:重新規劃結構的利器

當你要做的不只是加幾個欄位,而是要把整個 JSON 結構重新設計——例如把扁平的欄位收成巢狀物件,Manual Mapping 就顯得笨重。這時 JSON 模式登場。

情境:上游吐扁平 JSON,你要送到某個 API,那 API 要求的 payload 是巢狀結構。假設上游是:

{
  "id": "ORD-1234",
  "firstName": "小明",
  "lastName": "王",
  "amount": 1500
}

但下游 API 要求的格式是:

{
  "orderId": "ORD-1234",
  "customer": {
    "name": "王小明",
    "vip": true
  }
}

Manual Mapping 要處理巢狀比較彆扭;改用 JSON 模式一貼就搞定:

  1. Mode 切到 JSON

    節點最上方 Mode 下拉選 JSON。Fields to Set 消失,出現一個大文字框。

  2. 貼 JSON template

    把下面這段整段貼進文字框:

    {
      "orderId": "{{ $json.id }}",
      "customer": {
        "name": "{{ $json.lastName }}{{ $json.firstName }}",
        "vip": {{ $json.amount > 1000 }}
      }
    }

    字串類的值要用引號包("{{ ... }}"),布林/數字類不用引號({{ $json.amount > 1000 }} 直接是 true 或 false)。

  3. Include Other Input Fields 決定要不要保留原欄位

    JSON 模式一樣有這個 toggle。多數情況下你貼 JSON 就是要重新規劃結構,所以會 關掉——只留 JSON template 裡定義的欄位。

  4. Execute Node 檢查結構對不對

    Output 面板會吐出你貼的 JSON 結構,expression 都已經被填成實際值。這時就可以接下游的 HTTP Request 節點打 API。

觀念:JSON 模式的核心價值是「一眼看得出最終結構長什麼樣」。當結構複雜(多層巢狀、陣列),Manual Mapping 一條一條加會迷路;JSON 模式把最終樣貌直接展示在你面前,改也快、看也清楚。

實例:把 API 回來的巢狀 JSON 整成 Sheet 一列

把上一節 Set 節點的功力串起來,做一個實際會用到的短流程。情境:你用 HTTP Request 打了某個訂單 API,回來的 JSON 是巢狀結構,但你要把它 append 進 Google Sheets 的訂單追蹤表(一列 4 欄)。

上游 HTTP Request 節點的回應:

{
  "data": {
    "user": {
      "name": "王小明",
      "email": "[email protected]"
    },
    "order": {
      "id": "ORD-9527",
      "amount": 2800
    },
    "meta": {
      "ts": "2026-08-16T10:30:00Z"
    }
  }
}

Sheets 的 header:訂單編號 | 姓名 | 信箱 | 金額 | 時間 | VIP

中間放一個 Set 節點做整形:

  1. Set 節點 Mode 選 Manual Mapping

    因為要對應 Sheets 的固定欄位,一欄一欄設最清楚。

  2. Include Other Input Fields 關掉

    原本的巢狀結構帶到 Sheets 沒意義,關掉 toggle 只留下面設的六個欄位。

  3. Add Field 六次,依序設好

    逐欄對照 Sheets 的 header:

    NameTypeValue(Expression)
    訂單編號String{{ $json.data.order.id }}
    姓名String{{ $json.data.user.name }}
    信箱String{{ $json.data.user.email }}
    金額Number{{ $json.data.order.amount }}
    時間String{{ $json.data.meta.ts }}
    VIPString{{ $json.data.order.amount > 1000 ? 'VIP' : '一般' }}
  4. Execute Node 檢查扁平結構

    Output 應該是純扁平的 6 個欄位:{ 訂單編號: "ORD-9527", 姓名: "王小明", 信箱: "...", 金額: 2800, 時間: "...", VIP: "VIP" }。

  5. 接 Google Sheets Append 節點

    Sheets 節點 Data Mode 選 Map Each Column Below,因為欄位名字已經完全對齊 Sheets header,可以直接拖左邊面板的欄位到 Sheets 節點對應的輸入框——不用再打一次 expression。

這就是 Set 節點的典型工作模式:「把上游丟過來的亂七八糟 JSON,梳成下游好吃的樣子」。Sheets、Slack、Notion、Airtable 這些節點都很挑欄位格式,中間放一個 Set 讓資料整齊,下游節點就好設得多。

Universal Form Runner 4 節點 workflow 展示 Set/Edit Fields 用法
圖 18-1實戰範例:Universal Form Runner 只有 4 個節點,中間用 Set / Edit Fields 把表單資料整形成下游需要的欄位格式。
提示:養成習慣——複雜 workflow 每兩三個節點就放一個 Set 節點做中繼站。可讀性大幅提高、除錯也快。看到後面某個節點壞掉,第一步就是打開最近的 Set 節點看它吐出來的 JSON 對不對。

Set 節點 vs Function vs Code:什麼時候用哪個

n8n 裡有三個節點都能「整形資料」,但用途不同。你可能在舊教學看過 Function 節點,這裡一次講清楚:

節點寫程式嗎能力什麼時候用
Set (Edit Fields) 不用 加/改/刪欄位、簡單 expression、型別轉換 90% 的資料整形。優先選這個,能不寫程式就不寫
Function(已於 v0.198.0 合併進 Code) 要寫 JavaScript 能 loop、能呼叫少數 helper、比 Set 靈活但受限 不要用了。v0.198.0(2022 年年中)起被 Code 節點取代;新拉節點面板已找不到,只有 import 舊 workflow 才看得到
Code(新版) 要寫 JavaScript 或 Python 完整程式邏輯——loop、if / else、call npm module、複雜計算 Set 做不到的複雜邏輯。詳細在 第 20 章

怎麼選?先問自己:「這件事 Set 能做嗎?」能就用 Set,不能才升級 Code。Set 節點視覺化、看得懂、不易寫錯、執行快;Code 節點強大但要寫程式、要處理錯誤、非工程師接手比較痛苦。

注意:Function 節點在 v0.198.0(2022 年 6 月釋出)已經被 Code 節點取代,官方文件明確寫「Code node replaces Function and Function Item nodes」。舊 workflow 裡的 Function 節點目前還能跑(向後相容),但新拉節點面板搜「function」拉不到——只能拉到 Code。有新需求一律用 Code,不要想辦法把 Function 找回來用。

幾個 Set 節點的進階小技巧

1. 用 dot notation 加巢狀欄位(Manual Mapping 模式)

Manual Mapping 模式其實也能產出巢狀結構,訣竅是 Name 欄位用「點」串路徑:

  • Name = customer.name, Value = {{ $json.firstName }}
  • Name = customer.email, Value = {{ $json.email }}

Output 會是:{ customer: { name: "小明", email: "..." } }。省得切 JSON 模式。

2. 一次覆蓋多筆 items

Set 節點跟其他節點一樣,會自動對每一筆 item 執行一次。所以你不用寫 loop——上游丟 10 筆進來,Set 就會產出 10 筆整形後的 output。$json 在每一輪自動指向「當前這一筆 item」。

3. 用 Continue On Fail 讓錯誤 item 不擋整條流

Set 節點右上角 Settings 齒輪裡有 Continue On Fail。某一筆 item 的 expression 執行失敗(例:某欄位不存在導致 undefined.foo)時,如果沒開這個,整條 workflow 直接紅字停下。開了以後那筆 item 會標成 error 但流繼續跑,你可以在 output 看哪幾筆壞掉、其他繼續往下游走。

4. Set 節點也可以放在流程開頭當「假資料產生器」

還沒有真實 trigger、想先測後面幾個節點的邏輯?拉一個 Manual Trigger + Set 節點,Set 節點 Mode 選 JSON、貼一段假資料 JSON、Include Other Input Fields 關掉——這樣按 Execute Workflow 就會有一筆假資料流下去。debug 神器。

提示:如果你想「刪掉某個欄位」,Manual Mapping 沒有明確的 delete 動作。作法:Include Other Input Fields 打勾、Add Field 一個同名的欄位、Value 留空、Type 選什麼都行——欄位會變成空值。真的要移除欄位(key 都不留)就得用 Code 節點寫 delete item.json.欄位名。

常見卡關與怎麼救

症狀原因怎麼救
Set 完欄位不見了(原本有 email,下游拿不到) Include Other Input Fields 沒打勾(或舊版 Keep Only Set Fields 開了),你也沒在 Fields to Set 明列 email 打開 Include Other Input Fields toggle,或把要留的欄位都手動 Add Field 一遍
Expression 拿到 undefined 欄位路徑打錯——例如上游其實是 $json.name,你寫成 $json.data.user.name 先按 Execute Node 上游節點,看 output 面板實際 JSON 長什麼樣,照抄路徑;或者在左邊 input 面板點欄位名讓 n8n 自動填
加了欄位但下游節點沒吃到 下游節點的 expression 還在引舊欄位名(例:你把 email 改叫 customer_email,但下游還在打 $json.email) rename 欄位後,記得同步更新所有下游節點的 expression。改名字是有連鎖影響的
欄位名字有空格或中文,expression 找不到 JavaScript dot notation($json.欄 名)不支援空格 用中括號寫法:{{ $json['欄 名'] }}、{{ $json['姓 名'] }}。中括號可以吃任何字元
Value 明明打數字,Output 卻是字串 "123" Fields to Set 的 Type 設成 String,或 JSON 模式裡值用引號包了 Manual Mapping:Type 改 Number;JSON 模式:值不要用引號 "amount": {{ $json.amount }};或加型別轉換 {{ Number($json.amount) }}
切換模式後所有欄位不見 Manual Mapping 跟 JSON 模式的設定不共用。切模式=清空 Ctrl+Z 復原切回原模式;或決定好模式後再開始設欄位
JSON 模式跳紅字 Invalid JSON 字串欄位忘記用引號包、或多逗號少逗號 把 JSON 貼到 JSON validator(jsonlint.com)檢查;expression {{ }} 也要放在合法 JSON 位置,字串類要用引號 "{{ ... }}"
Manual Mapping 加了一堆欄位介面卡 Set 節點欄位太多(>50 個)時介面渲染會慢 改用 JSON 模式:50 個欄位在 JSON 文字框裡是很小的一坨,比 50 張視覺化卡片流暢

常見問題

Set 節點會影響 execution time 嗎?
幾乎不會。Set 節點完全在 n8n 本機記憶體處理,沒 API call、沒 I/O,一筆 item 的處理時間通常在 1 毫秒以下。就算你在一條 workflow 裡放五個 Set 節點做多次整形,總延遲也可以忽略。真正拖慢 workflow 的是 HTTP Request、SaaS 節點這類「要出去打別人 API」的節點,不是 Set。
一個 Set 節點能設幾個欄位?有沒有上限?
技術上沒有硬上限。但實務建議單一 Set 節點不要超過 30 個欄位——太多的話介面會卡、可讀性也差。真的欄位很多(例:資料同步要對映 50 個欄位),有兩個選擇:(1) 拆成兩個 Set 節點串在一起,每個負責一部分;(2) 改用 JSON 模式,50 個 key 在文字框裡很緊湊。
Set 節點跟 Code 節點差在哪?我什麼時候該升級?
差別是「能做的事」跟「用起來的門檻」的取捨。Set:不寫程式、視覺化、能做加改欄位/型別轉換/簡單條件;Code:要寫 JavaScript/Python、能寫 loop / if 邏輯/呼叫 npm module/處理陣列展開合併。升級 Code 的訊號:(1) 你發現一個 Value 欄位裡 expression 寫超過 5 行;(2) 你需要對陣列做 map / filter / reduce;(3) 你需要「跨 items 互相參照」的邏輯(例:把 10 筆 items 合成一筆)。這些情況 Set 做不到就換 Code,詳見 第 20 章。
新版介面為什麼把 Set 改名叫 Edit Fields?
因為「Set」對非工程師來說不夠直覺——programmer 才會把「設定某個值」叫 set;一般人看到「Set」會想成「一組」或搞不清楚是動詞還是名詞。改叫 Edit Fields (Set) 意圖直白得多:「編輯欄位」(括號還留 Set 讓老用戶認得)。這是 n8n 大約在 v1 前後(2023 上下)的介面翻修一環;Function 節點合併到 Code 是更早的 v0.198.0(2022 年 6 月)就發生的另一件事,兩者不是同一波。舊 workflow 裡的 Set 節點自動視為 Edit Fields (Set),功能完全一樣,不用擔心相容性。
Set 節點能不能對「陣列」欄位做整形?例如把 tags: ["a","b","c"] 變成 tags: "a, b, c"?
可以。用 expression 呼叫 JavaScript 陣列方法就行:Name = tags、Type = String、Value = {{ $json.tags.join(', ') }}。反過來想把字串切成陣列:{{ $json.csv.split(',') }}、Type 選 Array。單一 item 內的陣列處理 Set 都能做;但如果是「把整個 items 陣列展開或合併」(例:一筆 item 展開成三筆、或三筆合併成一筆),那要用 第 16 章的 Split In Batches / Merge 節點,或直接寫 Code。
Set 節點裡的 $now 是什麼時區?寫進 Sheets 會不會跑掉?
$now 是 n8n Luxon DateTime 物件,預設用 n8n instance 的時區(如果你的 n8n 部署在 Asia/Taipei 就是台北時間)。直接寫進 Sheets 有時 Sheets 會自作聰明轉時區。建議做法:Value 用 {{ $now.toFormat('yyyy-MM-dd HH:mm:ss') }} 直接產字串,Type 選 String,Sheets 那邊那欄先設「純文字」格式——這樣什麼時區、什麼格式都是你自己控制,最穩。
Include Other Input Fields 打勾時,如果我 set 的欄位名跟原欄位撞名,會發生什麼事?
你 set 的值會覆蓋原本的。例:input 有 email: "[email protected]",你在 Set 節點加一個 Field,Name = email、Value = 「已隱藏」——output 的 email 就是「已隱藏」。這是很方便的「就地改值」用法,例如把敏感欄位遮蔽、或把某欄的值標準化({{ $json.email.toLowerCase() }})。撞名時 set 值永遠贏,不會出錯也不會警告,直接覆蓋。
能不能在 Set 節點裡引用「另一個節點」的資料,而不是上一個節點?
可以,這是 n8n 很強的功能。Value 欄位用 {{ $('節點名稱').item.json.欄位 }} 就能拉任何前面節點的資料,不只上一個。例:workflow 開頭有一個 Webhook 節點名叫 Webhook,中間跑了三個節點,最後一個 Set 節點想同時拉 Webhook 的原始 payload 和上一步的計算結果——Value 可以寫 {{ $('Webhook').item.json.customer_id }} - {{ $json.result }}。這在複雜 workflow 裡是常用手法,比每一步都用 Set「保留欄位」乾淨得多。細節在 第 14 章expression 篇有完整範例,第 19 章的 subworkflow 也會用到類似技巧。