别再把 n8n 当“连线玩具”了
很多刚接触 n8n 的朋友,容易陷入一个误区:只知道拖拽节点,遇到复杂的逻辑就傻眼。比如,API 返回的数据结构太乱,想清洗一下字段;或者需要把一堆数据合并成一个对象,再发给下一个接口。
这时候,如果你只会用“Set”节点硬拼,工作流会变得又长又丑,维护起来简直是噩梦。作为 N8N大学 的首席主编,笔者必须告诉你:**n8n 的灵魂,在于 Function 节点。** 它能让你用 JavaScript 代码像手术刀一样精准地处理数据流转。
今天这篇硬核教程,我们就来彻底讲透如何用 Function 节点优雅地解决复杂数据问题。看完这篇,你的自动化水平至少提升两个档次。
Function 节点到底在干什么?
先用人话翻译一下:Function 节点就是一个黑盒子,你把数据从左边扔进去,中间写一段 JavaScript 代码处理它,然后从右边扔出去。
在 n8n 中,数据是以“JSON 对象”的形式在节点间流动的。Function 节点之所以强大,是因为它允许你:
- **遍历数组**:一次性处理 100 条数据,而不是手动复制粘贴 100 次。
- **逻辑判断**:如果 A 字段包含 B,就修改 C 字段。
- **格式转换**:把 XML 转成 JSON,或者把一维数组拍平成二维。
记住,你不需要写前端那种复杂的 UI 代码,这里只需要处理纯粹的数据逻辑。这正是 n8n 作为低代码工具的巅峰形态——**低代码 + 硬核代码的完美结合。**
实战场景:清洗并重组 API 返回的混乱数据
假设我们有一个场景:你从一个电商 API 获取了订单数据,但返回的 JSON 结构非常深,而且包含了很多不需要的字段。你的目标是提取 `order_id`、`total_price`,并把 `user_info` 里的 `name` 和 `email` 拉平到顶层,最后只输出一个干净的数组。
这就是典型的复杂数据流转场景。我们一步步来拆解。
步骤 1:准备输入数据(Input Data)
在 Function 节点中,你可以通过 `items` 变量访问所有输入数据。通常,一个 Item 代表一条数据。为了演示,我们假设输入是这样的一条数据:
[
{
"id": 12345,
"details": {
"price": 99.99,
"currency": "USD"
},
"customer": {
"profile": {
"fullName": "John Doe",
"contact": "john@example.com"
}
}
}
]
步骤 2:编写 JavaScript 逻辑
点击 Function 节点的“Code”区域,输入以下代码。注意看注释,这是 n8n Function 节点的核心写法。
// 1. 创建一个空数组,用来存放处理后的结果
const cleanedData = [];
// 2. 遍历输入的 items
// n8n 会自动将输入的 JSON 赋值给 items 变量
for (const item of items) {
// 获取深层数据(记得做防御性编程,防止报错)
const orderId = item.json.id;
const price = item.json.details ? item.json.details.price : 0;
const userName = item.json.customer?.profile?.fullName;
const userEmail = item.json.customer?.profile?.contact;
// 3. 构建新的 JSON 对象
const newItem = {
json: {
order_id: orderId,
total_amount: price,
customer_name: userName,
email: userEmail,
// 添加一个时间戳作为处理标记
processed_at: new Date().toISOString()
}
};
// 4. 将新对象推入数组
cleanedData.push(newItem);
}
// 5. 最后必须返回结果,否则后续节点拿不到数据
return cleanedData;
步骤 3:输出与验证
在 Function 节点后面接一个简单的“Debug”节点或者“IF”节点。
你会发现,原本嵌套极深的数据,被“拍”成了一个扁平、干净的结构。这就是代码处理数据的魅力——**精准、高效、可重复。**
进阶技巧:处理数组与合并数据
上面的例子是处理单条数据。但在实际工作中,我们经常需要处理“一对多”的关系。比如,你需要把多个 API 返回的数据合并到一个对象里。
假设你有两个输入数据流(通过 Merge 节点汇聚),你想根据 ID 合并它们的属性。
// 这是一个更高级的合并逻辑
const mergedMap = new Map();
// 第一步:遍历所有输入,按 ID 聚合
for (const item of items) {
const id = item.json.id;
if (!mergedMap.has(id)) {
mergedMap.set(id, { json: { id: id } });
}
const target = mergedMap.get(id).json;
// 将所有字段合并到一个对象中
// 注意:这里假设字段不冲突,如果冲突需要写逻辑判断
Object.assign(target, item.json);
}
// 第二步:将 Map 转换回 n8n 需要的数组格式
// 注意:n8n 的 items 是数组,每个元素是一个对象
return Array.from(mergedMap.values());
这段代码展示了如何利用 JavaScript 的 `Map` 对象实现去重和合并。这在处理数据库查询结果与 API 对比时非常有用。
避坑指南:90% 的人会犯的错误
虽然 Function 节点很强大,但新手很容易在这里“翻车”。笔者总结了两个最常见的坑:
1. 忘记返回值 (Return)
在普通 JavaScript 中,函数如果没有 return,通常会返回 `undefined`。但在 n8n 的 Function 节点里,如果你不 return 任何东西,或者 return 了错误的格式,**下游节点将收不到任何数据**,导致整个工作流中断。
硬核建议:永远确保你的代码最后返回的是一个符合 n8n 标准的数组对象,例如
[{ json: { ... } }]。
2. 异步处理 (Async/Await)
Function 节点默认是同步执行的。如果你需要在节点内部进行异步请求(比如用 axios 再次调用 API),你必须使用 async 函数写法,并且 n8n 的版本支持情况需注意。不过,笔者的建议是:尽量不要在 Function 节点里做 HTTP 请求。
为什么?因为 n8n 有专门的 HTTP Request 节点,它自带重试机制、错误处理和更直观的参数配置。在 Function 节点里硬写 HTTP 请求,调试起来会让你怀疑人生。把 Function 节点纯粹留给“数据计算”,把 IO 操作交给专业节点。
FAQ:关于 n8n Function 节点的常见疑问
Q1: 我需要专业的 JavaScript 开发经验才能用 Function 节点吗?
A: 不需要精通前端框架,但你需要懂基础的 JS 语法(对象、数组操作)。如果你会写 Excel 公式,那理解 JS 的逻辑思维不会太难。N8N大学 建议先从修改现成的代码片段开始。
Q2: Function 节点和 Set 节点有什么区别?
A: Set 节点适合简单的“键值对”重命名或静态赋值。Function 节点适合动态计算、循环遍历和复杂逻辑判断。简单说:Set 是“死”的,Function 是“活”的。
Q3: 代码写错了,怎么调试?
A: 善用 console.log()。在 Function 节点里打印变量,然后运行工作流,点击节点查看“Output”标签下的日志。这是最快定位问题的方法,比看报错提示更直观。
总结与资源
掌握 Function 节点,意味着你从 n8n 的“用户”进化为了 n8n 的“开发者”。它打破了预置节点的限制,让你能处理任何想象得到的数据逻辑。
记住我们的原则:能用现成节点解决的优先用现成节点,遇到复杂逻辑再祭出 Function 节点。
推荐阅读:
如果你在使用过程中遇到了具体的报错,欢迎在 N8N大学 的评论区留言,学长在线帮你排忧解难。