如果你已经在使用n8n构建自动化工作流,你会发现节点虽然功能强大,但有时候还是不够灵活。此时,n8n提供的内置方法与变量就成了你的"秘密武器"。
在深入学习方法之前,先理清两个重要的概念:
什么是表达式?
表达式是用{{ }}包裹的JavaScript代码片段,几乎可以在任何节点的任何字段中使用。
特点:
简单示例:
// 获取当前时间戳
{{ $now.toISO() }}
// 条件判断
{{ $json.status === 'active' ? '活跃' : '离线' }}
// 访问其他节点的数据
{{ $("HTTP Request").first().json.userId }}什么是Code节点?
Code节点允许你编写多行JavaScript或Python代码来处理数据。相比表达式,它提供了更多的灵活性和计算能力。
特点:
简单示例:
// 逐条处理模式:处理单个item
const orderData = $input.item.json;
const totalPrice = orderData.price * orderData.quantity;
return {
...orderData,
totalPrice: totalPrice
};这是最基础、也是最常用的一组方法。
| 方法 | 说明 | 使用场景 |
|---|---|---|
$json | 当前item的JSON数据简写 | 快速访问当前数据 |
$input.item | 当前处理的item完整对象 | 需要访问item的所有属性 |
$input.all() | 获取所有input items | 在Code节点中批量处理 |
$input.first() | 获取第一个item | 只需要第一条数据 |
$input.last() | 获取最后一个item | 只需要最后一条数据 |
$binary | 当前item的二进制数据 | 处理文件、图片等 |
假设你收到了一个包含用户信息的JSON数据:
{
"name": "张三",
"email": "zhangsan@example.com",
"age": 28,
"status": "active"
}需求:在后续节点中,只显示活跃用户的名字。
表达式解决方案:
{{ $json.status === 'active' ? $json.name : '用户未激活' }}Code节点解决方案:
const user = $input.item.json;
if (user.status === 'active') {
return {
json: {
displayName: user.name,
userEmail: user.email
}
};
} else {
return {
json: {
displayName: '用户未激活',
userEmail: null
}
};
}在Code节点中设置"Mode: Run Once for All Items",处理所有输入项:
// 获取所有items
const allItems = $input.all();
// 提取每条数据的特定字段
const userNames = allItems.map(item => {
return item.json.name;
});
// 返回处理结果
return [
{
json: {
totalUsers: allItems.length,
names: userNames,
firstUser: $input.first().json.name,
lastUser: $input.last().json.name
}
}
];当你需要在一个节点中引用之前节点的结果时,就需要这些方法。
| 方法 | 说明 |
|---|---|
$("<节点名>").all() | 获取指定节点的所有输出项 |
$("<节点名>").first() | 获取指定节点的第一个输出项 |
$("<节点名>").last() | 获取指定节点的最后一个输出项 |
$("<节点名>").item | 获取与当前item链接的上游item |
$("<节点名>").params | 获取该节点的参数设置 |
假设你有两个API节点:
{ userId: 123, name: "张三" }{ orderId: 456, amount: 999 }需求:在下游节点中合并这两个API的数据。
表达式方案:
{{
{
user: $("API Call 1").first().json,
order: $("API Call 2").first().json
}
}}Code节点方案:
// 获取两个API节点的数据
const userData = $("API Call 1").first().json;
const orderData = $("API Call 2").first().json;
// 合并数据
return [
{
json: {
...userData,
...orderData,
mergedAt: new Date().toISOString()
}
}
];n8n内置了Luxon库来处理日期和时间,让复杂的时间操作变得简单。
| 方法 | 说明 | 示例 |
|---|---|---|
$now | 当前时间(Luxon对象) | {{ $now.toISO() }} |
$today | 今天午夜时刻 | {{ $today.toISODate() }} |
// 获取当前时间戳
{{ $now.toISO() }}
// 输出:2025-12-05T11:11:00.000Z
// 格式化为中文日期
{{ $now.toFormat("yyyy年MM月dd日 HH:mm") }}
// 输出:2025年12月05日 11:11
// 计算7天后的日期
{{ $now.plus({ days: 7 }).toISODate() }}
// 输出:2025-12-12
// 判断是否是今天
{{ $json.timestamp > $today.toISO() ? '今天' : '之前' }}当你需要从复杂的JSON结构中提取特定数据时,JMESPath是最强大的工具。
$jmespath(expression, data)// 1. 获取数组中的所有email
{{ $jmespath("users[*].email", $json) }}
// 2. 筛选符合条件的用户(年龄>18)
{{ $jmespath("users[?age > '18']", $json) }}
// 3. 获取嵌套对象的值
{{ $jmespath("address.city", $json) }}
// 4. 统计数组长度
{{ $jmespath("length(items)", $json) }}
// 5. 排序(按age升序)
{{ $jmespath("sort_by(users, &age)", $json) }}假设你收到了这样的JSON数据:
{
"orders": [
{ "id": 1, "status": "completed", "amount": 100 },
{ "id": 2, "status": "pending", "amount": 200 },
{ "id": 3, "status": "completed", "amount": 150 }
]
}需求:只获取已完成的订单。
// 使用JMESPath提取
{{ $jmespath("orders[?status == 'completed'].amount", $json) }}
// 输出:[100, 150]这些方法帮助你访问当前工作流和执行的信息。
| 方法 | 说明 | 示例 |
|---|---|---|
$execution.id | 当前执行的唯一ID | {{ $execution.id }} |
$execution.mode | 执行模式(test或production) | {{ $execution.mode }} |
$workflow.id | 工作流ID | {{ $workflow.id }} |
$workflow.name | 工作流名称 | {{ $workflow.name }} |
$workflow.active | 工作流是否激活 | {{ $workflow.active }} |
$nodeVersion | 节点版本 | {{ $nodeVersion }} |
$itemIndex | 当前item的索引(从0开始) | {{ $itemIndex }} |
// 在返回结果中添加执行信息
return [
{
json: {
processedData: $json,
executionId: $execution.id,
executionMode: $execution.mode,
workflowName: $workflow.name,
processedAt: $now.toISO(),
itemIndex: $itemIndex
}
}
];n8n提供了一些简化常见操作的便利函数。
| 方法 | 说明 |
|---|---|
$if(condition, valueIfTrue, valueIfFalse) | 条件判断(三元操作符的替代) |
$ifEmpty(value, defaultValue) | 如果值为空则返回默认值 |
$evaluateExpression(expression) | 动态执行表达式字符串 |
$max(...) | 返回最大值 |
$min(...) | 返回最小值 |
// 方案1:使用$if方法
{{ $if($json.status === 'active', '激活', '未激活') }}
// 方案2:使用$ifEmpty处理空值
{{ $ifEmpty($json.nickname, $json.name) }}
// 如果nickname为空,则使用name
// 方案3:获取最大值
{{ $max($json.prices[0], $json.prices[1], $json.prices[2]) }}现在让我们构建一个完整的、可执行的工作流,综合应用所有学到的方法。
{
"name": "数据处理综合案例",
"nodes": [
{
"parameters": {},
"name": "Start",
"type": "n8n-nodes-base.start",
"typeVersion": 1,
"position": [250, 300]
},
{
"parameters": {
"method": "GET",
"url": "https://jsonplaceholder.typicode.com/users/1/posts",
"authentication": "none"
},
"name": "Fetch Orders",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [450, 300]
},
{
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "// 使用Code节点处理所有订单数据\nconst allOrders = $input.all();\n\n// 过滤已完成的订单\nconst completedOrders = allOrders.filter(order => {\n return order.json.completed === true;\n});\n\n// 为每个订单添加处理信息\nconst processedOrders = completedOrders.map((order, index) => {\n const orderData = order.json;\n const price = 100; // 示例价格\n const taxRate = 0.13; // 13%税率\n const taxAmount = price * taxRate;\n const totalWithTax = price + taxAmount;\n \n return {\n json: {\n orderId: orderData.id,\n title: orderData.title,\n originalPrice: price,\n taxAmount: taxAmount.toFixed(2),\n totalWithTax: totalWithTax.toFixed(2),\n processedAt: $now.toISO(),\n executionMode: $execution.mode,\n workflowName: $workflow.name,\n itemIndex: index\n }\n };\n});\n\n// 返回处理后的数据\nreturn processedOrders.length > 0 ? processedOrders : [{\n json: { message: '没有已完成的订单' }\n}];"
},
"name": "Process Data",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [650, 300]
},
{
"parameters": {
"jsCode": "// 汇总统计信息\nconst allItems = $input.all();\n\nconst summary = {\n totalOrders: allItems.length,\n totalRevenue: allItems.reduce((sum, item) => sum + parseFloat(item.json.totalWithTax || 0), 0).toFixed(2),\n totalTax: allItems.reduce((sum, item) => sum + parseFloat(item.json.taxAmount || 0), 0).toFixed(2),\n orders: allItems.map(item => item.json),\n generatedAt: $now.toISO(),\n workflowExecutionId: $execution.id\n};\n\nreturn [{\n json: summary\n}];"
},
"name": "Generate Report",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [850, 300]
}
],
"connections": {
"Start": {
"main": [
[{ "node": "Fetch Orders", "type": "main", "index": 0 }]
]
},
"Fetch Orders": {
"main": [
[{ "node": "Process Data", "type": "main", "index": 0 }]
]
},
"Process Data": {
"main": [
[{ "node": "Generate Report", "type": "main", "index": 0 }]
]
}
},
"settings": {}
}{
"totalOrders": 5,
"totalRevenue": "565.00",
"totalTax": "65.00",
"orders": [
{
"orderId": 1,
"title": "订单1",
"originalPrice": 100,
"taxAmount": "13.00",
"totalWithTax": "113.00",
"processedAt": "2025-12-05T11:11:00.000Z",
"executionMode": "production",
"workflowName": "数据处理综合案例",
"itemIndex": 0
}
// ... 更多订单项目
],
"generatedAt": "2025-12-05T11:11:00.000Z",
"workflowExecutionId": "abc123def456"
}// ❌ 错误:直接访问可能不存在的字段
{{ $json.user.profile.email }} // 如果user或profile不存在会报错
// ✅ 正确:使用可选链
{{ $json.user?.profile?.email }}
// ✅ 正确:使用$ifEmpty
{{ $ifEmpty($json.user.profile.email, '邮箱未设置') }}// ❌ 错误:$input不是函数
{{ $input(0) }}
// ✅ 正确:使用$input的方法
{{ $input.first().json }}
{{ $input.all().length }}// ❌ 错误:混淆JavaScript Date和Luxon DateTime
const date = new Date(); // JavaScript Date
{{ date.toISO() }} // 报错,Date没有toISO方法
// ✅ 正确:使用n8n提供的$now
{{ $now.toISO() }}在Code节点中,你可以使用console.log来调试:
const data = $input.item.json;
console.log("当前数据:", data); // 这会输出到n8n的日志中
console.log("执行模式:", $execution.mode);
console.log("工作流名称:", $workflow.name);
return [{ json: data }];// ❌ 低效:逐条执行,多次处理
// 如果有1000条数据,这会执行1000次
// ✅ 高效:一次性处理所有数据
// Mode: Run Once for All Items
const allItems = $input.all();
const processed = allItems.map(item => {
// 处理逻辑
return item;
});// ❌ 低效:在循环中调用API
for (const item of items) {
const response = await this.helpers.httpRequest({
method: 'GET',
url: `https://api.example.com/user/${item.userId}`
});
}
// ✅ 高效:一次性获取所有数据
const userIds = items.map(item => item.userId).join(',');
const response = await this.helpers.httpRequest({
method: 'GET',
url: `https://api.example.com/users?ids=${userIds}`
});// 在Code节点中先过滤,减少后续处理
const filtered = $input.all()
.filter(item => item.json.status === 'active')
.map(item => item.json);| 实践 | 说明 |
|---|---|
| 优先使用表达式 | 简单操作用表达式,避免创建额外节点 |
| Code节点用于复杂逻辑 | 当表达式无法解决时才使用Code |
| 添加数据验证 | 总是检查数据是否存在和有效 |
| 使用有意义的节点名 | 便于在表达式中引用和调试 |
| 记录审计信息 | 添加时间戳和执行信息,便于追踪 |
| 合理使用批量处理 | 大数据集时选择"一次运行所有项"模式 |
| 充分利用内置方法 | 减少依赖,提高工作流性能 |
n8n的内置方法与变量是构建高效自动化工作流的核心工具。通过本教程,你已经学到:
✅ 表达式和Code节点的区别与应用场景
✅ 如何访问和处理当前节点的输入数据
✅ 如何跨节点引用数据
✅ 强大的日期时间和JMESPath查询能力
✅ 工作流元数据的获取和使用
✅ 完整的实战工作流示例
✅ 常见错误和调试方法
[1] 官方文档: https://docs.n8n.io/code/builtin/overview/
[2] n8n系列教程: https://www.undsky.com/blog/?category=n8n%E6%95%99%E7%A8%8B#