[ PROMPT_NODE_28084 ]
n8n JavaScript 代码节点数据访问指南
[ SKILL_DOCUMENTATION ]
# 数据访问模式 - JavaScript 代码节点
在 n8n 代码节点中使用 JavaScript 访问数据的综合指南。
---
## 概览
在 n8n 代码节点中,你可以使用内置变量和方法访问来自前序节点的数据。了解使用哪种方法对于正确执行工作流至关重要。
**数据访问优先级**(按常用程度排序):
1. **`$input.all()`** - 最常用 - 批量操作、聚合
2. **`$input.first()`** - 非常常用 - 单个条目操作
3. **`$input.item`** - 常用 - 仅限“每个条目运行一次”模式
4. **`$node["NodeName"].json`** - 引用特定节点
5. **`$json`** - 直接访问当前条目(旧版,建议改用 `$input`)
---
## 模式 1:$input.all() - 处理所有条目
**用法**:批量处理最常用的模式
**适用场景:**
- 处理多条记录
- 聚合数据(求和、计数、平均值)
- 过滤数组
- 转换数据集
- 比较条目
- 排序或排名
### 基础用法
```javascript
// 获取前序节点的所有条目
const allItems = $input.all();
// allItems 是一个对象数组,结构如下:
// [
// {json: {id: 1, name: "Alice"}},
// {json: {id: 2, name: "Bob"}}
// ]
console.log(`接收到 ${allItems.length} 个条目`);
return allItems;
```
### 示例 1:过滤激活状态的条目
```javascript
const allItems = $input.all();
// 仅保留状态为 active 的条目
const activeItems = allItems.filter(item => item.json.status === 'active');
return activeItems;
```
### 示例 2:转换所有条目
```javascript
const allItems = $input.all();
// 映射到新结构
const transformed = allItems.map(item => ({
json: {
id: item.json.id,
fullName: `${item.json.firstName} ${item.json.lastName}`,
email: item.json.email,
processedAt: new Date().toISOString()
}
}));
return transformed;
```
### 示例 3:聚合数据
```javascript
const allItems = $input.all();
// 计算总额
const total = allItems.reduce((sum, item) => {
return sum + (item.json.amount || 0);
}, 0);
return [{
json: {
total,
count: allItems.length,
average: total / allItems.length
}
}];
```
### 示例 4:排序和限制数量
```javascript
const allItems = $input.all();
// 按分数获取前 5 名
const topFive = allItems
.sort((a, b) => (b.json.score || 0) - (a.json.score || 0))
.slice(0, 5);
return topFive.map(item => ({json: item.json}));
```
### 示例 5:按类别分组
```javascript
const allItems = $input.all();
// 按类别对条目进行分组
const grouped = {};
for (const item of allItems) {
const category = item.json.category || 'Uncategorized';
if (!grouped[category]) {
grouped[category] = [];
}
grouped[category].push(item.json);
}
// 转换为数组格式
return Object.entries(grouped).map(([category, items]) => ({
json: {
category,
items,
count: items.length
}
}));
```
### 示例 6:按 ID 去重
```javascript
const allItems = $input.all();
// 按 ID 移除重复项
const seen = new Set();
const unique = [];
for (const item of allItems) {
const id = item.json.id;
if (!seen.has(id)) {
seen.add(id);
unique.push(item);
}
}
return unique;
```
---
## 模式 2:$input.first() - 获取第一个条目
**用法**:单条目操作非常常用
**适用场景:**
- 前序节点返回单个对象
- 处理 API 响应
- 获取初始/第一个数据点
- 访问配置或元数据
### 基础用法
```javascript
// 获取前序节点的第一个条目
const firstItem = $input.first();
// 访问 JSON 数据
const data = firstItem.json;
console.log('第一个条目:', data);
return [{json: data}];
```
### 示例 1:处理单个 API 响应
```javascript
// 获取 API 响应(通常是单个对象)
const response = $input.first().json;
// 提取所需内容
return [{
json: {
userId: response.data.user.id,
userName: response.data.user.name,
status: response.status,
fetchedAt: new Date().toISOString()
}
}];
```
### 示例 2:转换单个对象
```javascript
const data = $input.first().json;
// 转换结构
return [{
json: {
id: data.id,
contact: {
email: data.email,
phone: data.phone
},
address: {
street: data.street,
city: data.city,
zip: data.zip
}
}
}];
```
### 示例 3:验证单个条目
```javascript
const item = $input.first().json;
// 验证逻辑
const isValid = item.email && item.email.includes('@');
return [{
json: {
...item,
valid: isValid,
validatedAt: new Date().toISOString()
}
}];
```
### 示例 4:提取嵌套数据
```javascript
const response = $input.first().json;
// 导航嵌套结构
const users = response.data?.users || [];
return users.map(user => ({
json: {
id: user.id,
name: user.profile?.name || 'Unknown',
email: user.contact?.email || 'no-email'
}
}));
```
### 示例 5:与其他方法结合使用
```javascript
// 获取第一个条目的数据
const firstData = $input.first().json;
// 使用它来过滤所有条目
const allItems = $input.all();
const matching = allItems.filter(item =>
item.json.category === firstData.targetCategory
);
return matching;
```
---
## 模式 3:$input.item - 当前条目(每个条目模式)
**用法**:在“每个条目运行一次”模式下常用
**适用场景:**
- 模式设置为 "Run Once for Each Item"
- 需要独立处理每个条目
- 针对每个条目的 API 调用或验证
- 针对条目的特定错误处理
**重要提示**:仅在“每个条目”模式下使用。在“所有条目”模式下将为 undefined。
### 基础用法
```javascript
// 在 "Run Once for Each Item" 模式下
const currentItem = $input.item;
const data = currentItem.json;
console.log('正在处理条目:', data.id);
return [{
json: {
...data,
processed: true
}
}];
```
### 示例 1:添加处理元数据
```javascript
const item = $input.item;
return [{
json: {
...item.json,
processed: true,
processedAt: new Date().toISOString(),
processingDuration: Math.random() * 1000 // 模拟耗时
}
}];
```
### 示例 2:针对每个条目的验证
```javascript
const item = $input.item;
const data = item.json;
// 验证此特定条目
const errors = [];
if (!data.email) errors.push('Email required');
if (!data.name) errors.push('Name required');
if (data.age && data.age 0 ? errors : undefined
}
}];
```
### 示例 3:针对条目的 API 调用
```javascript
const item = $input.item;
const userId = item.json.userId;
// 发起针对该条目的 API 调用
const response = await $helpers.httpRequest({
method: 'GET',
url: `https://api.example.com/users/${userId}/details`
});
return [{
json: {
...item.json,
details: response
}
}];
```
### 示例 4:条件处理
```javascript
const item = $input.item;
const data = item.json;
// 根据条目类型进行处理
if (data.type === 'premium') {
return [{
json: {
...data,
discount: 0.20,
tier: 'premium'
}
}];
} else {
return [{
json: {
...data,
discount: 0.05,
tier: 'standard'
}
}];
}
```
---
## 模式 4:$node - 引用其他节点
**用法**:较少见,但在特定场景下非常强大
**适用场景:**
- 需要来自特定命名节点的数据
- 合并来自多个节点的数据
- 访问有关工作流执行的元数据
### 基础用法
```javascript
// 获取特定节点的输出
const webhookData = $node["Webhook"].json;
const apiData = $node["HTTP Request"].json;
return [{
json: {
fromWebhook: webhookData,
fromAPI: apiData
}
}];
```
### 示例 1:合并多个来源
```javascript
// 引用多个节点
const webhook = $node["Webhook"].json;
const database = $node["Postgres"].json;
const api = $node["HTTP Request"].json;
return [{
json: {
combined: {
webhook: webhook.body,
dbRecords: database.length,
apiResponse: api.status
},
processedAt: new Date().toISOString()
}
}];
```
### 示例 2:跨节点对比
```javascript
const oldData = $node["Get Old Data"].json;
const newData = $node["Get New Data"].json;
// 对比
const changes = {
added: newData.filter(n => !oldData.find(o => o.id === n.id)),
removed: oldData.filter(o => !newData.find(n => n.id === o.id)),
modified: newData.filter(n => {
const old = oldData.find(o => o.id === n.id);
return old && JSON.stringify(old) !== JSON.stringify(n);
})
};
return [{
json: {
changes,
summary: {
added: changes.added.length,
removed: changes.removed.length,
modified: changes.modified.length
}
}
}];
```
### 示例 3:访问节点元数据
```javascript
// 从特定执行分支获取数据
const ifTrueBranch = $node["IF True"].json;
const ifFalseBranch = $node["IF False"].json;
// 使用已执行的分支
const result = ifTrueBranch || ifFalseBranch || {};
return [{json: result}];
```
---
## 关键点:Webhook 数据结构
**最常见的错误**:忘记 Webhook 数据嵌套在 `.body` 属性下。
### 问题所在
Webhook 节点会将所有传入数据封装在 `body` 属性中。这经常让开发者感到意外。
### 结构示例
```javascript
// Webhook 节点输出结构:
{
"headers": {
"content-type": "application/json",
"user-agent": "...",
// ... 其他请求头
},
"params": {},
"query": {},
"body": {
// ← 你的数据在这里
"name": "Alice",
"email": "[email protected]",
"message": "Hello!"
}
}
```
### 错误 vs 正确写法
```javascript
// ❌ 错误:尝试直接访问
const name = $json.name; // undefined
const email = $json.email; // undefined
// ✅ 正确:通过 .body 访问
const name = $json.body.name; // "Alice"
const email = $json.body.email; // "[email protected]"
// ✅ 正确:先提取 body
const webhookData = $json.body;
const name = webhookData.name; // "Alice"
const email = webhookData.email; // "[email protected]"
```
### 示例:完整的 Webhook 处理
```javascript
// 从前序节点获取 Webhook 数据
const webhookOutput = $input.first().json;
// 访问实际负载
const payload = webhookOutput.body;
// 如果需要,访问请求头
const contentType = webhookOutput.headers['content-type'];
// 如果需要,访问查询参数
const apiKey = webhookOutput.query.api_key;
// 处理实际数据
return [{
json: {
// 来自 Webhook body 的数据
userName: payload.name,
userEmail: payload.email,
message: payload.message,
// 元数据
receivedAt: new Date().toISOString(),
contentType: contentType,
authenticated: !!apiKey
}
}];
```
### POST 数据、查询参数和请求头
```javascript
const webhook = $input.first().json;
return [{
json: {
// POST body 数据
formData: webhook.body,
// 查询参数 (?key=value)
queryParams: webhook.query,
// HTTP 请求头
userAgent: webhook.headers['user-agent'],
contentType: webhook.headers['content-type'],
// 请求元数据
method: webhook.method, // POST, GET 等
url: webhook.url
}
}];
```
---
## 选择正确的模式
### 决策树
```
是否需要来自前序节点的所有条目?
├─ 是 → 使用 $input.all()
│
└─ 否 → 是否只需要第一个条目?
├─ 是 → 使用 $input.first()
│
└─ 否 → 是否处于“每个条目”模式?
├─ 是 → 使用 $input.item
│
└─ 否 → 是否需要特定节点的数据?
├─ 是 → 使用 $node["NodeName"]
└─ 否 → 使用 $input.first() (默认)
```
### 快速参考表
| 场景 | 使用方法 | 示例 |
|----------|----------|---------|
| 汇总所有金额 | `$input.all()` | `allItems.reduce((sum, i) => sum + i.json.amount, 0)` |
| 获取 API 响应 | `$input.first()` | `$input.first().json.data` |
| 独立处理每个条目 | `$input.item` | `$input.item.json` (每个条目模式) |
| 合并两个节点 | `$node["Name"]` | `$node["API"].json` |
| 过滤数组 | `$input.all()` | `allItems.filter(i => i.json.active)` |
| 转换单个对象 | `$input.first()` | `{...input.first().json, new: true}` |
| Webhook 数据 | `$input.first()` | `$input.first().json.body` |
---
## 常见错误
### 错误 1:无上下文使用 $json
```javascript
// ❌ 错误:$json 含义模糊
const value = $json.field;
// ✅ 正确:显式指定
const value = $input.first().json.field;
```
### 错误 2:忘记 .json 属性
```javascript
// ❌ 错误:尝试在条目对象上直接访问字段
const items = $input.all();
const names = items.map(item => item.name); // undefined
// ✅ 正确:通过 .json 访问
const names = items.map(item => item.json.name);
```
### 错误 3:在“所有条目”模式下使用 $input.item
```javascript
// ❌ 错误:$input.item 在“所有条目”模式下为 undefined
const data = $input.item.json; // 报错!
// ✅ 正确:使用合适的方法
const data = $input.first().json; // 或 $input.all()
```
### 错误 4:未处理空数组
```javascript
// ❌ 错误:如果没有条目会崩溃
const first = $input.all()[0].json;
// ✅ 正确:先检查长度
const items = $input.all();
if (items.length === 0) {
return [];
}
const first = items[0].json;
// ✅ 同样正确:使用 $input.first()
const first = $input.first().json; // 内置安全处理
```
### 错误 5:修改原始数据
```javascript
// ❌ 有风险:直接修改原始对象
const items = $input.all();
items[0].json.modified = true;
return items;
// ✅ 安全:创建新对象
const items = $input.all();
return items.map(item => ({
json: {
...item.json,
modified: true
}
}));
```
---
## 高级模式
### 模式:分页处理
```javascript
const currentPage = $input.all();
const pageNumber = $node["Set Page"].json.page || 1;
// 与之前的页面合并
const allPreviousPages = $node["Accumulator"]?.json.accumulated || [];
return [{
json: {
accumulated: [...allPreviousPages, ...currentPage],
currentPage: pageNumber,
totalItems: allPreviousPages.length + currentPage.length
}
}];
```
### 模式:条件节点引用
```javascript
// 根据条件访问不同节点
const condition = $input.first().json.type;
let data;
if (condition === 'api') {
data = $node["API Response"].json;
} else if (condition === 'database') {
data = $node["Database"].json;
} else {
data = $node["Default"].json;
}
return [{json: data}];
```
---
## 总结
**最常用模式**:
1. `$input.all()` - 处理多个条目、批量操作
2. `$input.first()` - 单个条目、API 响应
3. `$input.item` - “每个条目”模式下的处理
**关键规则**:
- Webhook 数据位于 `.body` 属性下
**最佳实践**:
- 显式表达:使用 `$input.first().json.field` 而非 `$json.field`
- 始终检查 null/undefined
- 根据你的运行模式(所有条目 vs 每个条目)选择合适的方法
数据来源:claude-code-templates(MIT),中文翻译由 AI 生成。详见关于我们。
粤公网安备44030002003366号