别再让API返回的JSON地狱折磨你的神经了
笔者最近在N8N大学的社群里看到不少同学在抱怨:n8n虽然好用,但一旦遇到复杂的API数据结构,光靠“移动数据”、“合并数据”这些原生节点,流程图就得画成蜘蛛网。特别是当数据嵌套层级深、需要批量处理、或者需要做复杂的逻辑判断时,拖拽节点反而成了负担。
其实,n8n早就给了我们一把“瑞士军刀”——Code节点。它内置了JavaScript环境,允许你直接写代码来清洗、转换和重组数据。今天这篇实战指南,N8N大学就带你突破低代码的束缚,用几行代码解决那些看似无解的复杂数据处理难题。
Code节点到底能干什么?
在n8n里,Code节点(JavaScript)通常作为流程中的“瑞士军刀”存在。它不仅仅是执行代码,更是连接两个异构系统的桥梁。当你需要:
- 将扁平数据转换为树状结构(JSON嵌套)
- 批量生成动态请求参数(循环逻辑)
- 根据复杂条件过滤数组(例如:金额大于100且状态为“完成”)
- 计算哈希值或进行简单的加密解密
这就是Code节点大显身手的时刻。它允许你访问流程中的所有输入数据(items),并灵活输出。
实战场景一:清洗嵌套的API响应数据
假设你调用了一个CRM系统的API,返回的数据结构像俄罗斯套娃一样复杂:
{
"data": {
"users": [
{ "id": 1, "profile": { "name": "Alice", "contacts": { "email": "a@test.com" } } },
{ "id": 2, "profile": { "name": "Bob", "contacts": { "email": "b@test.com" } } }
]
}
}
你只需要所有用户的name和email。如果用原生节点,你需要经历“解析JSON -> 提取users -> 循环 -> 提取profile -> 提取contacts -> 提取name/email”等一系列操作。但在Code节点里,只需几行代码:
// 读取输入数据(假设输入是上一步的HTTP请求结果)
const rawData = items[0].json;
// 使用 map 方法扁平化数据
const output = rawData.data.users.map(user => {
return {
id: user.id,
name: user.profile.name,
email: user.profile.contacts.email
};
});
// 输出结果,n8n会自动将其拆分为多个 item
return output;
关键点: Code节点的返回值如果是数组(Array),n8n会自动将数组中的每个对象拆分为一个独立的Item流。这在后续连接HTTP请求节点进行批量操作时极其有用。
实战场景二:动态构建批量请求参数
这是一个进阶技巧。比如你从Google Sheets读取了一列产品ID,需要向Shopify API批量获取详情。通常HTTP Request节点很难直接处理这种动态数组输入。
在Code节点中,你可以利用JavaScript强大的数组处理能力:
// 假设输入是一个包含多个ID的数组
const ids = items.map(item => item.json.product_id);
// 构建GraphQL查询字符串(Shopify常用)
const query = `
query {
nodes(ids: [${ids.map(id => `"gid://shopify/Product/${id}"`).join(',')}]) {
... on Product {
title
handle
}
}
}
`;
// 返回构建好的对象,供下一个HTTP Request节点使用
return [{ json: { query } }];
这里我们用到了items.map遍历所有输入,然后用join拼接字符串。这种“数据预处理”逻辑,用原生节点几乎无法实现,但用JavaScript只是一行代码的事。
实战场景三:复杂的逻辑过滤与数据合并
有些场景下,你需要根据业务逻辑对数据进行“裁决”。例如,对比两个来源的数据,只保留差异部分。
假设你有两组数据:一组是旧的库存列表,一组是新的API抓取结果。你需要找出新增的SKU。
const oldList = items[0].json.data; // 假设这是第一个输入分支
const newList = items[1].json.data; // 假设这是第二个输入分支
// 将旧列表转为Set以便快速查询
const oldSkus = new Set(oldList.map(item => item.sku));
// 筛选出新列表中旧列表没有的SKU
const newItems = newList.filter(item => !oldSkus.has(item.sku));
return newItems.map(item => ({ json: item }));
这段代码利用了JavaScript的Set对象实现高效的O(1)时间复杂度查找,避免了双重循环带来的性能损耗(这在处理成千上万条数据时至关重要)。
避坑指南:Code节点的常见陷阱
虽然Code节点很强大,但新手容易在以下地方翻车:
- 上下文对象搞错: 在n8n Code节点中,数据流通过
items变量访问。千万不要试图使用input.first().json这种旧版n8n的语法(除非你用的是极老版本)。现在的标准写法是items[0].json。 - 返回值格式: Code节点返回的必须是一个对象数组(Array of Objects)。如果你直接返回一个字符串或数字,n8n会报错。如果你希望输出单个Item,记得写成
return [{ json: { key: value } }]。 - 性能陷阱: 虽然JavaScript很快,但如果你在Code节点里处理百万级数据的循环(例如复杂的正则替换),可能会导致n8n Worker内存溢出。遇到大数据量,建议先在数据库层或API查询层做过滤。
FAQ:关于n8n Code节点的高频疑问
Q1: 我不懂JavaScript,还能用n8n处理复杂数据吗?
A: 可以,但有上限。n8n的原生节点覆盖了80%的常规需求。如果你的逻辑极其复杂(比如需要递归、复杂的正则或数学计算),建议花半小时学习一下JS的基础语法。笔者见过很多非程序员同事,通过复制粘贴修改示例代码,解决了实际问题。
Q2: Code节点里能引入第三方库吗(比如lodash, moment)?
A: 默认情况下不能直接require('lodash')。n8n运行在受限的沙箱环境中。但是,你可以将库的代码直接复制粘贴到Code节点中(在Function页面),或者使用n8n提供的原生工具库(如require('crypto')用于加密)。对于日期处理,建议直接用JS原生Date对象或n8n的Expression功能。
Q3: 为什么我的Code节点报错“Cannot read property 'json' of undefined”?
A: 这通常意味着你的输入数据流是空的(Empty items)。检查上一个节点是否成功执行,或者是否传回了空数据。在代码开头加上防御性编程:if (!items || items.length === 0) return [];。
总结与资源
Code节点是n8n从“好用”进阶到“强大”的关键分水岭。它打破了节点功能的边界,让你能用最熟悉的逻辑去处理最棘手的数据。
N8N大学建议: 不要一开始就沉迷于写复杂的代码。先尝试用原生节点组合,遇到瓶颈时再引入Code节点。记住,低代码的核心是“效率”,而不是“炫技”。
如果你想获取更多n8n Code节点的实战模板,欢迎访问 N8N大学 (n8ndx.com),我们整理了一份《Code节点100例》开源库,助你快速上手。