n8n 变量与表达式系统 - 动态工作流的核心
n8n 的表达式系统是其最强大的功能之一,它让工作流能够动态地处理数据、做出决策和适应不同的场景。今天我们来深入学习这个系统的各个方面。
表达式基础语法
基本格式
n8n 表达式使用双花括号包围:
javascript
{{ expression }}
数据引用
当前节点数据
javascript
{{ $json.fieldName }} // 引用当前数据的字段
{{ $json["field name"] }} // 字段名包含空格或特殊字符
{{ $json.user.name }} // 嵌套对象
{{ $json.items[0] }} // 数组元素
{{ $json.items.length }} // 数组长度
其他节点数据
javascript
{{ $node["Node Name"].json }} // 引用指定节点的数据
{{ $node["HTTP Request"].json.result }} // 引用节点的特定字段
{{ $('Node Name').item.json }} // 另一种引用方式
全局变量
javascript
{{ $now }} // 当前时间
{{ $today }} // 今天日期
{{ $workflow.id }} // 工作流 ID
{{ $workflow.name }} // 工作流名称
{{ $execution.id }} // 执行 ID
{{ $execution.mode }} // 执行模式
数据类型操作
字符串操作
javascript
// 基本字符串操作
{{ $json.name.toLowerCase() }} // 转小写
{{ $json.name.toUpperCase() }} // 转大写
{{ $json.name.trim() }} // 去除首尾空格
{{ $json.name.length }} // 字符串长度
// 字符串拼接
{{ $json.firstName + ' ' + $json.lastName }}
{{ `Hello, ${$json.name}!` }} // 模板字符串
// 字符串查找和替换
{{ $json.text.includes('keyword') }} // 是否包含
{{ $json.text.indexOf('keyword') }} // 查找位置
{{ $json.text.replace('old', 'new') }} // 替换
{{ $json.text.split(',') }} // 分割字符串
// 字符串截取
{{ $json.text.substring(0, 10) }} // 截取前10个字符
{{ $json.text.slice(-5) }} // 截取后5个字符
数字操作
javascript
// 数学运算
{{ $json.price * 1.1 }} // 乘法
{{ $json.total / $json.count }} // 除法
{{ $json.amount + $json.tax }} // 加法
{{ $json.budget - $json.spent }} // 减法
{{ $json.value % 10 }} // 取余
// 数学函数
{{ Math.round($json.value) }} // 四舍五入
{{ Math.floor($json.value) }} // 向下取整
{{ Math.ceil($json.value) }} // 向上取整
{{ Math.abs($json.value) }} // 绝对值
{{ Math.max($json.a, $json.b) }} // 最大值
{{ Math.min($json.a, $json.b) }} // 最小值
// 数字格式化
{{ $json.price.toFixed(2) }} // 保留2位小数
{{ $json.value.toLocaleString() }} // 本地化格式
数组操作
javascript
// 数组基本操作
{{ $json.items.length }} // 数组长度
{{ $json.items[0] }} // 第一个元素
{{ $json.items.slice(-1)[0] }} // 最后一个元素
// 数组方法
{{ $json.tags.join(', ') }} // 连接数组元素
{{ $json.numbers.sort() }} // 排序
{{ $json.items.reverse() }} // 反转
// 数组过滤和映射
{{ $json.items.filter(item => item.active) }}
{{ $json.numbers.map(n => n * 2) }}
{{ $json.items.find(item => item.id === 123) }}
// 数组聚合
{{ $json.numbers.reduce((sum, n) => sum + n, 0) }}
{{ $json.items.some(item => item.urgent) }}
{{ $json.items.every(item => item.valid) }}
对象操作
javascript
// 对象属性
{{ Object.keys($json.user) }} // 获取所有键
{{ Object.values($json.user) }} // 获取所有值
{{ Object.entries($json.user) }} // 获取键值对数组
// 对象合并
{{ Object.assign({}, $json.user, $json.profile) }}
{{ {...$json.user, ...$json.profile} }}
// 属性检查
{{ $json.user.hasOwnProperty('email') }}
{{ 'email' in $json.user }}
日期时间处理
基本日期操作
javascript
// 当前时间
{{ $now }} // 当前时间戳
{{ $today }} // 今天日期
{{ new Date() }} // 当前日期对象
// 日期创建
{{ new Date($json.dateString) }} // 从字符串创建
{{ new Date($json.timestamp) }} // 从时间戳创建
// 日期格式化
{{ $now.toISOString() }} // ISO 格式
{{ $now.toDateString() }} // 日期字符串
{{ $now.toTimeString() }} // 时间字符串
{{ $now.toLocaleDateString('zh-CN') }} // 本地化日期
日期计算
javascript
// 日期加减
{{ $now.plus({days: 7}) }} // 7天后
{{ $now.minus({hours: 2}) }} // 2小时前
{{ $now.plus({months: 1, days: 15}) }} // 1个月15天后
// 日期比较
{{ $json.startDate < $json.endDate }} // 日期比较
{{ $now.diff($json.createdAt, 'days') }} // 天数差
{{ $now.diff($json.createdAt, 'hours') }} // 小时差
// 日期格式化
{{ $now.format('YYYY-MM-DD') }} // 自定义格式
{{ $now.format('YYYY-MM-DD HH:mm:ss') }}
{{ $now.format('dddd, MMMM Do YYYY') }}
时区处理
javascript
// 时区转换
{{ $now.tz('Asia/Shanghai') }} // 转换到指定时区
{{ $now.utc() }} // 转换到 UTC
{{ $now.local() }} // 转换到本地时区
// 时区信息
{{ $now.tz('Asia/Shanghai').format('Z') }} // 时区偏移
{{ $now.tz('Asia/Shanghai').zoneName() }} // 时区名称
条件表达式
三元运算符
javascript
// 基本三元运算
{{ $json.age >= 18 ? 'adult' : 'minor' }}
{{ $json.score > 60 ? 'pass' : 'fail' }}
// 嵌套三元运算
{{ $json.score >= 90 ? 'A' : $json.score >= 80 ? 'B' : $json.score >= 70 ? 'C' : 'D' }}
// 空值处理
{{ $json.name || 'Unknown' }} // 空值默认值
{{ $json.email ?? 'no-email@example.com' }} // null/undefined 默认值
复杂条件
javascript
// 逻辑运算
{{ $json.age >= 18 && $json.hasLicense }}
{{ $json.type === 'premium' || $json.type === 'vip' }}
{{ !$json.isDeleted }}
// 范围检查
{{ $json.score >= 60 && $json.score <= 100 }}
{{ ['active', 'pending'].includes($json.status) }}
// 正则表达式
{{ /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test($json.email) }}
{{ $json.phone.match(/^\d{11}$/) }}
高级表达式技巧
函数定义和调用
javascript
// 定义辅助函数
{{
(() => {
const formatCurrency = (amount) => {
return new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: 'CNY'
}).format(amount);
};
return formatCurrency($json.price);
})()
}}
// 复杂数据处理
{{
(() => {
const data = $json.items;
const grouped = data.reduce((acc, item) => {
const category = item.category || 'other';
if (!acc[category]) acc[category] = [];
acc[category].push(item);
return acc;
}, {});
return Object.keys(grouped).map(category => ({
category,
items: grouped[category],
count: grouped[category].length,
total: grouped[category].reduce((sum, item) => sum + item.value, 0)
}));
})()
}}
错误处理
javascript
// 安全的属性访问
{{ $json.user?.profile?.name || 'Unknown' }}
{{ $json.items?.[0]?.title || 'No title' }}
// Try-catch 表达式
{{
(() => {
try {
return JSON.parse($json.jsonString);
} catch (error) {
return { error: 'Invalid JSON', original: $json.jsonString };
}
})()
}}
// 数据验证
{{
(() => {
const email = $json.email;
if (!email) return { valid: false, error: 'Email is required' };
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return { valid: false, error: 'Invalid email format' };
}
return { valid: true, email: email.toLowerCase() };
})()
}}
环境变量和配置
环境变量访问
javascript
// 访问环境变量
{{ $env.API_KEY }} // 环境变量
{{ $env.DATABASE_URL }} // 数据库连接
{{ $env.NODE_ENV || 'development' }} // 带默认值
// 配置管理
{{
(() => {
const config = {
development: {
apiUrl: 'http://localhost:3000',
debug: true
},
production: {
apiUrl: 'https://api.example.com',
debug: false
}
};
const env = $env.NODE_ENV || 'development';
return config[env];
})()
}}
动态配置
javascript
// 基于时间的配置
{{
(() => {
const hour = new Date().getHours();
if (hour >= 9 && hour <= 17) {
return {
priority: 'high',
timeout: 5000,
retries: 3
};
} else {
return {
priority: 'low',
timeout: 10000,
retries: 1
};
}
})()
}}
// 基于数据的配置
{{
(() => {
const userType = $json.userType;
const configs = {
premium: { limit: 1000, features: ['advanced', 'priority'] },
standard: { limit: 100, features: ['basic'] },
trial: { limit: 10, features: ['basic'] }
};
return configs[userType] || configs.trial;
})()
}}
性能优化
表达式缓存
javascript
// 缓存复杂计算结果
{{
(() => {
const cacheKey = `calc_${$json.id}`;
if ($workflow.context[cacheKey]) {
return $workflow.context[cacheKey];
}
// 复杂计算
const result = expensiveCalculation($json.data);
// 缓存结果
$workflow.context[cacheKey] = result;
return result;
})()
}}
避免重复计算
javascript
// 将计算结果存储在变量中
{{
(() => {
const user = $json.user;
const now = new Date();
const age = Math.floor((now - new Date(user.birthDate)) / (365.25 * 24 * 60 * 60 * 1000));
return {
...user,
age,
isAdult: age >= 18,
category: age >= 65 ? 'senior' : age >= 18 ? 'adult' : 'minor'
};
})()
}}
调试表达式
调试技巧
javascript
// 添加调试信息
{{
(() => {
const debug = {
input: $json,
timestamp: new Date().toISOString(),
nodeId: $node.id,
workflowId: $workflow.id
};
console.log('Debug info:', debug);
// 实际处理逻辑
const result = processData($json);
return {
result,
debug: $env.NODE_ENV === 'development' ? debug : undefined
};
})()
}}
表达式测试
javascript
// 创建测试用例
{{
(() => {
const testCases = [
{ input: { age: 25 }, expected: 'adult' },
{ input: { age: 16 }, expected: 'minor' },
{ input: { age: 70 }, expected: 'senior' }
];
const categorizeAge = (age) => {
if (age >= 65) return 'senior';
if (age >= 18) return 'adult';
return 'minor';
};
const results = testCases.map(test => ({
...test,
actual: categorizeAge(test.input.age),
passed: categorizeAge(test.input.age) === test.expected
}));
return {
testResults: results,
allPassed: results.every(r => r.passed),
actualResult: categorizeAge($json.age)
};
})()
}}
实际应用案例
动态 API 端点
javascript
// 根据环境和用户类型构建 API URL
{{
(() => {
const baseUrl = $env.NODE_ENV === 'production'
? 'https://api.example.com'
: 'http://localhost:3000';
const version = $json.userType === 'premium' ? 'v2' : 'v1';
const endpoint = $json.action || 'default';
return `${baseUrl}/api/${version}/${endpoint}`;
})()
}}
智能路由
javascript
// 基于多个条件的智能路由
{{
(() => {
const data = $json;
const hour = new Date().getHours();
// 紧急情况
if (data.priority === 'urgent') {
return 'urgent_queue';
}
// 工作时间
if (hour >= 9 && hour <= 17) {
if (data.type === 'technical') return 'tech_support';
if (data.type === 'billing') return 'billing_team';
return 'general_support';
}
// 非工作时间
return 'after_hours_queue';
})()
}}
小结
n8n 的变量和表达式系统是创建动态工作流的核心:
- 掌握基本语法:理解数据引用和表达式格式
- 熟练使用内置函数:字符串、数字、日期、数组操作
- 善用条件表达式:实现复杂的业务逻辑
- 优化性能:避免重复计算,合理使用缓存
- 调试和测试:确保表达式的正确性
下一篇文章,我们将学习定时任务和调度系统,这是自动化工作流的重要组成部分。
记住,强大的表达式系统需要谨慎使用。过于复杂的表达式会影响可读性和维护性,适当时候应该考虑使用 Code 节点来实现复杂逻辑。