6、n8n 中写自己的代码(JavaScript)

工作原理

该工作流是一个关于 n8n 中Code node的实践教程,通过一个简单的数据处理任务,涵盖了基础与进阶概念。

  1. 提供示例数据:工作流以一个用户样本列表开始。
  2. 逐项处理( Run Once for Each Item :第一个代码节点遍历每个用户来计算其 fullNameage 。这展示了使用 $input.item.json 进行逐项数据操作的基础方法。
  3. 获取外部数据(高级) :第二个代码节点演示了更高级的功能。针对每个用户,它使用内置的 this.helpers.httpRequest 函数调用外部 API(genderize.io),通过预测性别来丰富数据。
  4. 批量处理所有项目( Run Once for All Items :第三个代码节点接收完整增强后的用户列表,仅运行一次。它使用 $items() 访问整个列表并计算 averageAge ,最终返回一个汇总项。
  5. 创建二进制文件 :最终的代码节点再次获取完整丰富的用户列表,并创建一个二进制 CSV 文件,展示如何在 JavaScript 中使用二进制数据 Buffer

设置步骤

▶️ STARTING POINT: Sample Data

这些节点为教程准备数据。

  1. 1. Sample Data:创建一个用户列表。你可以在这里自由修改数值进行实验!
  2. 2. Split Out Users:将列表拆分成多个 items,每个用户一个。这样做是为了让下一个 Code 节点能够逐一处理它们。

⚙️ LESSON 1: Processing Each Item

此节点处于 "Run Once for Each Item" 模式。它会针对每个用户执行一次。

目标: 丰富每个用户的数据。

关键概念:

  • $input.item.json:访问当前正在处理的 item 的数据。
  • return { ... }:返回一个对象,作为该 item 的新输出。...user 技巧可以保留原始数据。

运行 workflow 并查看此节点的输出:你会看到多个 items,每个都新增了 fullNameage

js 复制代码
// This code runs for EACH user individually.

// 1. Get the data for the current item
const user = $input.item.json;

// 2. Perform operations
const fullName = `${user.firstName} ${user.lastName}`;

const birthDate = new Date(user.birthDate);
const ageDiffMs = Date.now() - birthDate.getTime();
const ageDate = new Date(ageDiffMs);
const age = Math.abs(ageDate.getUTCFullYear() - 1970);

console.log(`Processing user: ${fullName}, Age: ${age}`);

// 3. Return the new data, keeping the original fields
return {
  ...user, // This keeps the original data (firstName, lastName, etc.)
  fullName: fullName,
  age: age
};

🚀 LESSON 2: Using Helpers

此节点同样会针对每个 item 运行,但演示了一个强大且进阶的功能。

目标: 通过在代码中调用外部 API 来丰富数据。

关键概念:

  • this.helpers.httpRequest:一个内置函数,可直接发起 API 调用。非常适合处理动态 URL,或者在调用前后需要加入逻辑的情况。
  • await:这里使用它是因为 API 调用是一个 异步 操作。

查看输出:每个用户现在都有了从网络获取的 gender 数据!

js 复制代码
// ADVANCED: This code calls an external API for each user.

// 1. Get the data for the current item
const user = $input.item.json;

// 2. Use a helper function to make an HTTP request
// 根据名字来猜测性别。
const url = `https://api.genderize.io?name=${user.firstName}`;

console.log(`Fetching external data for ${user.firstName} from ${url}`)

// this.helpers.httpRequest 是一个强大的内置函数。
// 我们使用 await,因为这是一个异步操作。
const response = await this.helpers.httpRequest({ url: url, json: true });

// 3. 返回原始数据与新的 API 数据的合并结果
return {
  ...user, // Keep all existing data (fullName, age, etc.)
  gender: response.gender,
  genderProbability: response.probability
};

⚙️ LESSON 3: Processing All Items at Once

此节点处于 "Run Once for All Items" 模式。它只运行一次,并能同时访问所有 items。

目标: 聚合数据以生成汇总信息。

关键概念:

  • $items():返回一个包含上一个节点所有 items 的 数组
  • return [ { json: { ... } } ]:返回一个数组,其中包含一个带有最终结果的新 item。

查看此节点的输出:只有一个 item,其中包含用户总数和他们的平均年龄。

js 复制代码
// This code runs only ONCE for ALL users.

// 1. Get all items from the previous node
const allUsers = $items();

// 2. Perform an aggregation
const totalAge = allUsers.reduce((sum, item) => {
  return sum + item.json.age;
}, 0);

const userCount = allUsers.length;
const averageAge = totalAge / userCount;

console.log(`Calculated average age for ${userCount} users.`);

// 3. Return a single new item with the result
return [
  {
    json: {
      totalUsers: userCount,
      averageAge: parseFloat(averageAge.toFixed(2)) // Format to 2 decimal places
    }
  }
];

📄 LESSON 4: Creating Files

目标: 聚合所有 items 并生成一个二进制文件(此处示例为 CSV)。 模式: Run Once for All Items

关键概念:

  • $("4. Fetch External Data (Advanced)").all():获取第 4 步中的所有 items 数组。
  • this.helpers.prepareBinaryData:将原始数据(如文本字符串)转换为 n8n 可用的二进制文件。
  • Buffer:JavaScript 中处理二进制数据的标准方式。
js 复制代码
// LESSON 4 (EXPERT): Creating a binary file.

// This node runs only ONCE for ALL items.

// 1. Get all items from the previous node
const allUsers = $("4. Fetch External Data (Advanced)").all();

// 2. Create a CSV string from the data
let csvContent = "FullName,Age,GenderGuess,ProcessedBy\n"; // CSV Header

for (const item of allUsers) {
  const user = item.json;
  const row = `"${user.fullName}",${user.age},${user.gender},n8n`;
  csvContent += row + "\n";
}

// 3. Use a helper to create a binary file from the string
const binaryData = await this.helpers.prepareBinaryData(Buffer.from(csvContent), 'user_report.csv');

// 4. Return a new item containing the binary data
return [
  {
    json: {
      reportGenerated: new Date().toISOString(),
      userCount: allUsers.length
    },
    binary: {
      'report': binaryData
    }
  }
];

最后

json 复制代码
{
  "name": "6、n8n 代码节点(JavaScript)",
  "nodes": [
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "38ce3db6-ce1d-4091-9645-39e674ad1782",
              "name": "users",
              "type": "array",
              "value": "=[{\"firstName\":\"Alice\",\"lastName\":\"Smith\",\"birthDate\":\"1990-05-15\"},{\"firstName\":\"Bob\",\"lastName\":\"Jones\",\"birthDate\":\"1985-11-22\"},{\"firstName\":\"Charlie\",\"lastName\":\"Brown\",\"birthDate\":\"2001-02-10\"}, {\"firstName\":\"Alex\",\"lastName\":\"Garcia\",\"birthDate\":\"1995-07-30\"}]"
            }
          ]
        },
        "options": {}
      },
      "id": "92c04b23-66f8-483d-b70f-cecf0ee51e85",
      "name": "1. Sample Data",
      "type": "n8n-nodes-base.set",
      "position": [
        -240,
        208
      ],
      "typeVersion": 3.4
    },
    {
      "parameters": {
        "fieldToSplitOut": "users",
        "options": {}
      },
      "id": "03127769-8716-4907-af60-56906d9eecdb",
      "name": "2. Split Out Users",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -16,
        208
      ],
      "typeVersion": 1
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// This code runs for EACH user individually.\n\n// 1. Get the data for the current item\nconst user = $input.item.json;\n\n// 2. Perform operations\nconst fullName = `${user.firstName} ${user.lastName}`;\n\nconst birthDate = new Date(user.birthDate);\nconst ageDiffMs = Date.now() - birthDate.getTime();\nconst ageDate = new Date(ageDiffMs);\nconst age = Math.abs(ageDate.getUTCFullYear() - 1970);\n\nconsole.log(`Processing user: ${fullName}, Age: ${age}`);\n\n// 3. Return the new data, keeping the original fields\nreturn {\n  ...user, // This keeps the original data (firstName, lastName, etc.)\n  fullName: fullName,\n  age: age\n};"
      },
      "id": "c425e7f1-f0ac-4a28-8881-14a3305617d3",
      "name": "3. Process Each User",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        208
      ],
      "typeVersion": 2
    },
    {
      "parameters": {
        "jsCode": "// This code runs only ONCE for ALL users.\n\n// 1. Get all items from the previous node\nconst allUsers = $items();\n\n// 2. Perform an aggregation\nconst totalAge = allUsers.reduce((sum, item) => {\n  return sum + item.json.age;\n}, 0);\n\nconst userCount = allUsers.length;\nconst averageAge = totalAge / userCount;\n\nconsole.log(`Calculated average age for ${userCount} users.`);\n\n// 3. Return a single new item with the result\nreturn [\n  {\n    json: {\n      totalUsers: userCount,\n      averageAge: parseFloat(averageAge.toFixed(2)) // Format to 2 decimal places\n    }\n  }\n];"
      },
      "id": "d766b8d3-349a-484b-ab1b-25e980b459ee",
      "name": "5. Calculate Average Age",
      "type": "n8n-nodes-base.code",
      "position": [
        1104,
        208
      ],
      "typeVersion": 2
    },
    {
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// ADVANCED: This code calls an external API for each user.\n\n// 1. Get the data for the current item\nconst user = $input.item.json;\n\n// 2. Use a helper function to make an HTTP request\n// 根据名字来猜测性别。\nconst url = `https://api.genderize.io?name=${user.firstName}`;\n\nconsole.log(`Fetching external data for ${user.firstName} from ${url}`)\n\n// this.helpers.httpRequest 是一个强大的内置函数。\n// 我们使用 await,因为这是一个异步操作。\nconst response = await this.helpers.httpRequest({ url: url, json: true });\n\n// 3. 返回原始数据与新的 API 数据的合并结果\nreturn {\n  ...user, // Keep all existing data (fullName, age, etc.)\n  gender: response.gender,\n  genderProbability: response.probability\n};"
      },
      "id": "74690167-680d-42ce-94f1-50eac60f5853",
      "name": "4. Fetch External Data (Advanced)",
      "type": "n8n-nodes-base.code",
      "position": [
        704,
        208
      ],
      "typeVersion": 2
    },
    {
      "parameters": {
        "content": "#### ▶️ STARTING POINT: Sample Data\n\n这些节点为教程准备数据。\n\n1. **`1. Sample Data`**:创建一个用户列表。你可以在这里自由修改数值进行实验!\n2. **`2. Split Out Users`**:将列表拆分成多个 items,每个用户一个。这样做是为了让下一个 Code 节点能够逐一处理它们。",
        "height": 420,
        "width": 440,
        "color": 5
      },
      "id": "134ae4a5-1264-48ad-afae-d6333be9f2a6",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -304,
        -32
      ],
      "typeVersion": 1
    },
    {
      "parameters": {
        "content": "#### ⚙️ LESSON 1: Processing Each Item\n\n此节点处于 **\"Run Once for Each Item\"** 模式。它会针对每个用户执行一次。\n\n**目标:** 丰富每个用户的数据。\n\n**关键概念:**\n\n* `$input.item.json`:访问当前正在处理的 item 的数据。\n* `return { ... }`:返回一个对象,作为该 item 的新输出。`...user` 技巧可以保留原始数据。\n\n运行 workflow 并查看此节点的输出:你会看到多个 items,每个都新增了 `fullName` 和 `age`。",
        "height": 580,
        "width": 380,
        "color": 7
      },
      "id": "2c17a395-08f2-4ea2-90b8-8ca1824080d0",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        -192
      ],
      "typeVersion": 1
    },
    {
      "parameters": {
        "content": "#### 🚀 ADVANCED LESSON 2: Using Helpers\n\n此节点同样会针对每个 item 运行,但演示了一个强大且进阶的功能。\n\n**目标:** 通过在代码中调用外部 API 来丰富数据。\n\n**关键概念:**\n\n* `this.helpers.httpRequest`:一个内置函数,可直接发起 API 调用。非常适合处理动态 URL,或者在调用前后需要加入逻辑的情况。\n* `await`:这里使用它是因为 API 调用是一个 *异步* 操作。\n\n查看输出:每个用户现在都有了从网络获取的 `gender` 数据!\n",
        "height": 600,
        "width": 380,
        "color": 6
      },
      "id": "af1478ac-3a95-4543-957f-95a6b0755962",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        -208
      ],
      "typeVersion": 1
    },
    {
      "parameters": {
        "content": "#### ⚙️ LESSON 3: Processing All Items at Once\n\n此节点处于 **\"Run Once for All Items\"** 模式。它只运行一次,并能同时访问所有 items。\n\n**目标:** 聚合数据以生成汇总信息。\n\n**关键概念:**\n\n* `$items()`:返回一个包含上一个节点所有 items 的 **数组**。\n* `return [ { json: { ... } } ]`:返回一个数组,其中包含一个带有最终结果的新 item。\n\n查看此节点的输出:只有一个 item,其中包含用户总数和他们的平均年龄。\n",
        "height": 580,
        "width": 380,
        "color": 7
      },
      "id": "c71f067c-8286-48bc-be1c-b2267d80980b",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        960,
        -192
      ],
      "typeVersion": 1
    },
    {
      "parameters": {
        "jsCode": "// LESSON 4 (EXPERT): Creating a binary file.\n\n// This node runs only ONCE for ALL items.\n\n// 1. Get all items from the previous node\nconst allUsers = $(\"4. Fetch External Data (Advanced)\").all();\n\n// 2. Create a CSV string from the data\nlet csvContent = \"FullName,Age,GenderGuess,ProcessedBy\\n\"; // CSV Header\n\nfor (const item of allUsers) {\n  const user = item.json;\n  const row = `\"${user.fullName}\",${user.age},${user.gender},n8n`;\n  csvContent += row + \"\\n\";\n}\n\n// 3. Use a helper to create a binary file from the string\nconst binaryData = await this.helpers.prepareBinaryData(Buffer.from(csvContent), 'user_report.csv');\n\n// 4. Return a new item containing the binary data\nreturn [\n  {\n    json: {\n      reportGenerated: new Date().toISOString(),\n      userCount: allUsers.length\n    },\n    binary: {\n      'report': binaryData\n    }\n  }\n];"
      },
      "id": "8d4b3c1b-d662-47ab-95ce-8c580f460424",
      "name": "6. Create a Binary File (Expert)",
      "type": "n8n-nodes-base.code",
      "position": [
        1504,
        208
      ],
      "typeVersion": 2
    },
    {
      "parameters": {
        "content": "#### 📄 EXPERT LESSON 4: Creating Files\n\n**目标:** 聚合所有 items 并生成一个二进制文件(此处示例为 CSV)。\n**模式:** `Run Once for All Items`\n\n**关键概念:**\n\n* `$(\"4. Fetch External Data (Advanced)\").all()`:获取第 4 步中的所有 items 数组。\n* `this.helpers.prepareBinaryData`:将原始数据(如文本字符串)转换为 n8n 可用的二进制文件。\n* `Buffer`:JavaScript 中处理二进制数据的标准方式。\n",
        "height": 580,
        "width": 380,
        "color": 3
      },
      "id": "c487b09b-ee2a-40be-ba4d-6f63f7564022",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1360,
        -192
      ],
      "typeVersion": 1
    },
    {
      "parameters": {},
      "id": "c6d72fe5-c323-4d60-b65b-cdb67ab7e07a",
      "name": "Start Tutorial",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -528,
        208
      ],
      "typeVersion": 1
    }
  ],
  "pinData": {},
  "connections": {
    "1. Sample Data": {
      "main": [
        [
          {
            "node": "2. Split Out Users",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start Tutorial": {
      "main": [
        [
          {
            "node": "1. Sample Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2. Split Out Users": {
      "main": [
        [
          {
            "node": "3. Process Each User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3. Process Each User": {
      "main": [
        [
          {
            "node": "4. Fetch External Data (Advanced)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5. Calculate Average Age": {
      "main": [
        [
          {
            "node": "6. Create a Binary File (Expert)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "4. Fetch External Data (Advanced)": {
      "main": [
        [
          {
            "node": "5. Calculate Average Age",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "25462711-c86b-4066-9a1d-0c20f8231738",
  "meta": {
    "instanceId": "54c9e2e31753f3c874da48cdbf9552e23a88fbc2e067ac67b23af8418a890097"
  },
  "id": "oObgugBmC9LTnAb8",
  "tags": []
}
相关推荐
机器之心23 分钟前
7年了,OpenAI官方给出五代GPT对比,网友却怀念起「狂野」初代
人工智能·openai
量子位3 小时前
4o-mini华人领队也离职了,这次不怪小扎
openai·gemini
机器之心8 小时前
机器人也会「摸鱼」了?宇树G1赛后葛优瘫刷美女视频,网友:比人还懂享受生活
人工智能·openai
新智元8 小时前
Meta没做的,英伟达做了!全新架构吞吐量狂飙6倍,20万亿Token训练
人工智能·openai
新智元8 小时前
Hinton 预言成真!AI 接管美国一半白领,牛津哈佛扎堆转行做技工
人工智能·openai
得物技术8 小时前
基于TinyMce富文本编辑器的客服自研知识库的技术探索和实践|得物技术
前端·aigc·openai
杨杨杨大侠8 小时前
04 - 步骤执行器设计 🔧
后端·workflow
李大腾腾1 天前
5、n8n 中调用 API
openai·workflow
waynaqua1 天前
FastAPI开发AI应用三:添加深度思考功能
python·openai·deepseek