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": []
}
相关推荐
楚莫识1 天前
Comet AI 浏览器免费开放了,还送 Perplexity Pro 会员!
openai·ai编程·cursor
机器之心1 天前
刚刚,Thinking Machines Lab博客提出在策略蒸馏,Qwen被cue 38次
人工智能·openai
量子位2 天前
OpenAI IPO计划第一步曝光,奥特曼骚操作看傻华尔街
openai
新智元2 天前
马斯克「世界模拟器」首曝,1 天蒸馏人类 500 年驾驶经验!擎天柱同脑进化
人工智能·openai
新智元2 天前
LeCun 怒揭机器人最大骗局,坦白 Llama 与我无瓜!
人工智能·openai
机器之心2 天前
三百年几何猜想被推翻,数学家首次发现「穿不过去」的多面体
人工智能·openai
机器之心2 天前
打造图像编辑领域的ImageNet?苹果用Nano Banana开源了一个超大数据集
人工智能·openai
AAA阿giao3 天前
深入理解 OpenAI AIGC 模型与 Node.js 实战:从零构建歌词生成应用
aigc·openai
用户6600676685394 天前
从零构建 AI 歌词生成器:Node.js + OpenAI SDK + Git
node.js·openai
机器之心5 天前
死磕「文本智能」,多模态研究的下一个前沿
人工智能·openai