Skip to content

理解数据结构#

在本章节中,您将了解 n8n 的数据结构,并学习如何使用 Code 节点 来转换数据和模拟节点输出。

n8n 的数据结构#

从基本概念上讲,n8n 节点发挥着提取(Extract)、转换(Transform)、加载(Load)(ETL)工具的作用。这些节点允许您从多个不同来源访问(提取)数据,以特定方式修改(转换)这些数据,并将其传递(加载)到需要的位置。

在工作流中从一个节点传递到另一个节点的数据必须采用能够被每个节点识别和解释的格式(结构)。在 n8n 中,这种必需的结构是对象数组。

关于对象数组

数组是值的列表。数组可以是空的,也可以包含多个元素。每个元素存储在列表中的位置(索引)上,从0开始,可以通过索引号引用。例如,在数组 ["Leonardo", "Michelangelo", "Donatello", "Raphael"]; 中,元素 Donatello 存储在索引2处。

对象存储的是键值对,而不是像数组中那样存储在编号索引处的值。这些对的顺序并不重要,因为可以通过引用键名来访问值。例如,下面的对象包含两个属性(namecolor):

1
2
3
4
{
	name: 'Michelangelo',
	color: 'blue',
}

对象数组是包含一个或多个对象的数组。例如,下面的数组 turtles 包含四个对象:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
var turtles = [
	{
		name: 'Michelangelo',
		color: 'orange',
	},
	{
		name: 'Donatello',
		color: 'purple',
	},
	{
		name: 'Raphael',
		color: 'red',
	},
	{
		name: 'Leonardo',
		color: 'blue',
	}
];

您可以使用点表示法 object.property 来访问对象的属性。例如,turtles[1].color 获取第二个乌龟的颜色。

从一个节点发送到另一个节点的数据是以 JSON 对象数组的形式发送的。这个集合中的元素称为项(items)。

n8n 节点对传入数据的每个项执行其操作。

客户数据存储节点中的项

使用 Code 节点创建数据集#

现在您已经熟悉了 n8n 的数据结构,可以使用它来创建自己的数据集或模拟节点输出。为此,请使用 Code 节点 编写 JavaScript 代码,定义具有以下结构的对象数组:

1
2
3
4
5
6
7
return [
	{
		json: {
			apple: 'beets',
		}
	}
];

例如,代表忍者神龟的对象数组在 Code 节点中会显示如下:

Code 节点中的对象数组

JSON 对象

请注意,这个对象数组包含一个额外的键:json。n8n 要求您将数组中的每个对象包装在另一个对象中,并使用 json 作为键。

n8n 数据结构示意图

最佳实践是按照 n8n 使用的正确结构传递数据。但如果您忘记为某个项目添加 json 键也不必担心,n8n(版本 0.166.0 及以上)会自动添加。

您还可以使用嵌套键值对,例如如果您想定义主要颜色和次要颜色。在这种情况下,需要将键值对进一步用花括号 {} 包裹。

n8n 数据结构视频

这个演讲 更详细地解释了 n8n 的数据结构。

练习#

在 Code 节点中,创建一个名为 myContacts 的对象数组,其中包含 nameemail 属性,且 email 属性进一步拆分为 personalwork

显示解决方案

Code 节点 的 JavaScript 代码字段中,您需要编写以下代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
var myContacts = [
	{
		json: {
			name: 'Alice',
			email: {
				personal: 'alice@home.com',
				work: 'alice@wonderland.org'
			},
		}
	},
	{
		json: {
			name: 'Bob',
			email: {
				personal: 'bob@mail.com',
				work: 'contact@thebuilder.com'
				},
		}
	},
];

return myContacts;

当您执行 Code 节点 时,结果应如下所示:

Code 节点的执行结果

在 Code 节点中引用节点数据#

就像您可以使用表达式来引用其他节点的数据一样,您也可以在 Code 节点 中使用一些方法和变量

在继续下一个练习之前,请确保您已阅读这些页面。

练习#

让我们在前一个练习的基础上继续,之前你使用了 Code 节点创建了一个包含两个联系人姓名和邮箱的数据集。现在,将第二个 Code 节点连接到第一个节点。在新节点中,编写代码创建一个名为 workEmail 的新列,该列引用第一个联系人的工作邮箱。

显示解决方案

Code 节点 的 JavaScript 代码字段中,你需要编写以下代码:

1
2
3
let items = $input.all();
items[0].json.workEmail = items[0].json.email['work'];
return items;

当你执行 Code 节点 时,结果应该如下图所示:

Code 节点引用

数据转换#

某些节点传入的数据可能具有与 n8n 使用的数据结构不同的格式。在这种情况下,您需要转换数据,以便每个数据项能够被单独处理。

两种最常见的数据转换操作是:

  • 从一个数据项创建多个数据项
  • 从多个数据项创建单个数据项

针对上述目的,有几种转换数据的方法:

  • 使用 n8n 的数据转换节点。这些节点可以修改包含列表(数组)的传入数据结构,而无需在代码节点中使用 JavaScript 代码:
    • 使用拆分节点将包含列表的单个数据项拆分为多个数据项。
    • 使用聚合节点将独立的数据项或其部分内容分组为单个数据项。
  • 使用代码节点编写 JavaScript 函数,通过对所有项运行一次模式修改传入数据的结构:
    • 要从单个数据项创建多个数据项,可以使用如下 JavaScript 代码。此示例假设数据项有一个名为 data 的键,其值为数组形式:[{ "data": [{<item_1>}, {<item_2>}, ...] }]
      1
      2
      3
      4
      5
      return $input.first().json.data.map(item => {
          return {
              json: item
          }
      });
      
    • 要从多个数据项创建单个数据项,可以使用如下 JavaScript 代码:
      1
      2
      3
      4
      5
      6
      7
      return [
      	{
          	json: {
          		data_object: $input.all().map(item => item.json)
          	}
          }
        ];
      

这些 JavaScript 示例假设您要转换的是整个输入数据。如上面的练习所示,您也可以通过识别数据项列表中的特定字段来执行任一操作。例如,如果我们的 workEmail 示例在单个字段中包含多个电子邮件,我们可以运行如下代码:

1
2
3
4
5
6
let items = $input.all();
return items[0].json.workEmail.map(item => {
	return {
		json: item
	}
});

练习#

  1. 使用 HTTP Request 节点 向 PokéAPI https://pokeapi.co/api/v2/pokemon 发起 GET 请求。(该 API 不需要认证)。
  2. 使用 Split Out 节点 转换 results 字段中的数据。
  3. 使用 Code 节点 转换 results 字段中的数据。
显示解决方案
  1. 要从 PokéAPI 获取宝可梦数据,使用 HTTP Request 节点 执行以下参数配置:
    • 认证方式: 无
    • 请求方法: GET
    • URL: https://pokeapi.co/api/v2/pokemon
  2. 要使用 Split Out 节点 转换数据,将此节点连接到 HTTP Request 节点 并设置以下参数:
    • 待拆分字段: results
    • 包含: 不包含其他字段
  3. 要使用 Code 节点 转换数据,将此节点连接到 HTTP Request 节点 并在 JavaScript 代码字段中编写以下代码:
    1
    2
    3
    4
    5
    6
    let items = $input.all();
    return items[0].json.results.map(item => {
    	return {
    		json: item
    	}
    });