N8N中文教程
使用 n8n/Getting_started/Text_courses/Level_two

合并与拆分数据#

在本章中,您将学习如何合并与拆分数据,以及在哪些情况下执行这些操作可能是有用的。

合并数据#

在某些情况下,您可能需要合并(组合)来自不同来源的数据并进行处理。

合并数据可能包括:

  • 从多个来源创建一个数据集。
  • 在多个系统之间同步数据。这可能包括删除重复数据,或在一个系统的数据发生变化时更新另一个系统中的数据。

单向同步 vs. 双向同步

在**单向同步(one-way sync)**中,数据仅在一个方向上同步。其中一个系统作为唯一的“真相来源”(single source of truth)。当主系统中的信息发生变化时,辅助系统会自动更新;但如果辅助系统中的信息发生更改,则不会反映到主系统中。

在**双向同步(two-way sync)**中,数据在两个系统之间双向同步。无论哪一个系统中的信息发生变化,另一个系统都会自动随之更新。

这篇博客教程 解释了如何在两个客户关系管理(CRM)系统之间实现单向和双向数据同步。

在 n8n 中,您可以使用 Merge 节点 来合并来自两个不同节点的数据,该节点提供了多种合并选项:

  • Append(追加)
  • Combine(组合)
    • 按字段合并(Merge by Fields):要求输入的字段相匹配
    • 按位置合并(Merge by Position)
    • 组合所有可能的组合(Combine all possible combinations)
  • 选择分支(Choose Branch)

请注意,组合 > 按字段合并(Combine > Merge by Fields) 要求你输入用于匹配的字段。这些字段在各个数据源之间应包含相同的值,以便 n8n 能正确地将数据匹配在一起。在 合并节点(Merge node) 中,它们被称为 Input 1 FieldInput 2 Field合并节点中的属性输入字段合并节点中的属性输入字段 使用点表示法引用嵌套属性 如果你想在 合并节点(Merge node) 的参数 Input 1 FieldInput 2 Field 中引用嵌套值,则需要以点表示法(dot notation)格式输入属性键(作为文本,而非表达式)。 注意 你也可以通过别名 Join(连接) 找到 合并节点(Merge node)。如果你熟悉 SQL 中的连接操作,这个名称可能更直观。

合并练习#

构建一个工作流,将来自“客户数据存储节点(Customer Datastore node)”和“代码节点(Code node)”的数据进行合并。

  1. 添加一个 合并节点(Merge node),其 Input 1 来自 客户数据存储节点(Customer Datastore node)Input 2 来自 代码节点(Code node)
  2. 客户数据存储节点(Customer Datastore node) 中,执行操作 获取所有人(Get All People)
  3. 代码节点(Code node) 中,创建一个包含两个对象的数组,每个对象具有三个属性:namelanguagecountry,其中 country 属性包含两个子属性:codename
    • 使用客户数据库中两位人物的信息填写这些属性的值。
    • 例如,Jay Gatsby 的语言为 English,国家名称为 United States。
  4. 合并节点(Merge node) 中,尝试不同的合并选项。

显示解决方案 本练习的工作流如下所示: 用于合并数据的工作流练习用于合并数据的工作流练习

如果你使用 Keep Matches(保留匹配项)选项,并以“name”作为匹配字段来合并数据,结果应如下所示(注意:此示例仅包含 Jay Gatsby;你得到的结果可能因所选角色而异): Merge 节点在“保留匹配项”选项下的输出Merge 节点在“保留匹配项”选项下的输出

要查看节点的配置,你可以将下方的 JSON 工作流代码复制并粘贴到你的编辑器界面(Editor UI)中:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108

| ``` { "meta":{ "templateCredsSetupCompleted":true, "instanceId":"cb484ba7b742928a2048bf8829668bed5b5ad9787579adea888f05980292a4a7" }, "nodes":[ { "parameters":{ "mode":"combine", "mergeByFields":{ "values":[ { "field1":"name", "field2":"name" } ] }, "options":{} }, "id":"578365f3-26dd-4fa6-9858-f0a5fdfc413b", "name":"Merge", "type":"n8n-nodes-base.merge", "typeVersion":2.1, "position":[ 720, 580 ] }, { "parameters":{}, "id":"71aa5aad-afdf-4f8a-bca0-34450eee8acc", "name":"When clicking "Execute workflow"", "type":"n8n-nodes-base.manualTrigger", "typeVersion":1, "position":[ 260, 560 ] }, { "parameters":{ "operation":"getAllPeople" }, "id":"497174fe-3cab-4160-8103-78b44efd038d", "name":"Customer Datastore (n8n training)", "type":"n8n-nodes-base.n8nTrainingCustomerDatastore", "typeVersion":1, "position":[ 500, 460 ] }, { "parameters":{ "jsCode":"return [\n {\n 'name': 'Jay Gatsby',\n 'language': 'English',\n 'country': {\n 'code': 'US',\n 'name': 'United States'\n }\n \n }\n \n];" }, "id":"387e8a1e-e796-4f05-8e75-7ce25c786c5f", "name":"Code", "type":"n8n-nodes-base.code", "typeVersion":2, "position":[ 500, 720 ] } ], "connections":{ "When clicking "Execute workflow"":{ "main":[ [ { "node":"Customer Datastore (n8n training)", "type":"main", "index":0 }, { "node":"Code", "type":"main", "index":0 } ] ] }, "Customer Datastore (n8n training)":{ "main":[ [ { "node":"Merge", "type":"main", "index":0 } ] ] }, "Code":{ "main":[ [ { "node":"Merge", "type":"main", "index":1 } ] ] } }, "pinData":{} }

---|---

循环操作#

在某些情况下,你可能需要对数组中的每个元素或每条数据项执行相同的操作(例如向通讯录中的每个联系人发送消息)。从技术上讲,你需要通过循环来遍历这些数据。 n8n 通常会自动处理此类重复性任务,因为节点会对每个数据项运行一次,因此你通常无需在工作流中显式构建循环。 然而,存在一些节点和操作的例外情况,在这些情况下你需要手动在工作流中构建循环。 要在 n8n 工作流中创建循环,你需要将一个节点的输出连接到前一个节点的输入,并添加一个 If 节点 来判断何时停止循环。

将数据分批处理#

如果你需要处理大量传入的数据、多次执行 Code 节点,或避免触发 API 的速率限制,最好将数据拆分为批次(组)并逐批处理。 对于这类场景,请使用 Loop Over Items 节点。该节点会将输入数据按指定的批次大小进行分割,并在每次迭代时返回预定义数量的数据。

Loop Over Items 节点的执行过程 当所有输入项都被划分为批次并传递给工作流中的下一个节点后,Loop Over Items 节点 就会停止执行,因此无需额外添加 If 节点 来终止循环。

循环/分批练习#

构建一个工作流,读取 Medium 和 dev.to 的 RSS 源。该工作流应包含以下三个节点:

  1. 一个 Code 节点,返回 Medium (https://medium.com/feed/n8n-io) 和 dev.to (https://dev.to/feed/n8n) 的 RSS 地址 URL。
  2. 一个 Loop Over Items 节点,设置 Batch Size: 1,接收来自 Code 节点RSS Read 节点 的输入,并对各项进行迭代。
  3. 一个 RSS Read 节点,获取由表达式传入的 Medium RSS 地址:{{ $json.url }}
    • RSS Read 节点 是一种例外节点,它仅处理接收到的第一个数据项,因此必须使用 Loop Over Items 节点 才能遍历多个项目。

显示解决方案

1. 添加一个 **Code 节点**。你可以通过多种方式格式化代码,其中一种方式是:
   * 将 **Mode(模式)** 设置为 `Run Once for All Items`(对所有项仅运行一次)。
   * 将 **Language(语言)** 设置为 `JavaScript`。
   * 复制下面的代码并粘贴到 JavaScript 代码编辑器中:

1 2 3 4 5 6 7 8 9 10 11 12 13

| ```
let urls = [
{
  json: {
    url: 'https://medium.com/feed/n8n-io'
  }
},
{
  json: {
    url: 'https://dev.to/feed/n8n'
  }
}
];
return urls;

---|--- 2. 添加一个 Loop Over Items 节点,并将其连接到 Code 节点

  • Batch Size(批处理大小) 设置为 1
  1. Loop Over Items 节点 会自动添加一个名为 "Replace Me" 的节点。将该节点替换为 RSS Read 节点
    • URL 设置为使用来自 Code 节点的 URL:{{ $json.url }}

该练习的工作流如下所示: 从两个博客获取 RSS 源的工作流从两个博客获取 RSS 源的工作流

要查看节点的配置,可以复制下方的 JSON 工作流代码,并粘贴到你的编辑器界面(Editor UI)中:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107

| ``` { "meta":{ "templateCredsSetupCompleted":true, "instanceId":"cb484ba7b742928a2048bf8829668bed5b5ad9787579adea888f05980292a4a7" }, "nodes":[ { "parameters":{}, "id":"ed8dc090-ae8c-4db6-a93b-0fa873015c25", "name":"When clicking "Execute workflow"", "type":"n8n-nodes-base.manualTrigger", "typeVersion":1, "position":[ 460, 460 ] }, { "parameters":{ "jsCode":"let urls = [\n {\n json: {\n url: 'https://medium.com/feed/n8n-io'\n }\n },\n {\n json: {\n url: 'https://dev.to/feed/n8n'\n } \n }\n]\n\nreturn urls;" }, "id":"1df2a9bf-f970-4e04-b906-92dbbc9e8d3a", "name":"Code", "type":"n8n-nodes-base.code", "typeVersion":2, "position":[ 680, 460 ] }, { "parameters":{ "options":{} }, "id":"3cce249a-0eab-42e2-90e3-dbdf3684e012", "name":"Loop Over Items", "type":"n8n-nodes-base.splitInBatches", "typeVersion":3, "position":[ 900, 460 ] }, { "parameters":{ "url":"={{ $json.url }}", "options":{} }, "id":"50e1c1dc-9a5d-42d3-b7c0-accc31636aa6", "name":"RSS Read", "type":"n8n-nodes-base.rssFeedRead", "typeVersion":1, "position":[ 1120, 460 ] } ], "connections":{ "When clicking "Execute workflow"":{ "main":[ [ { "node":"Code", "type":"main", "index":0 } ] ] }, "Code":{ "main":[ [ { "node":"Loop Over Items", "type":"main", "index":0 } ] ] }, "Loop Over Items":{ "main":[ null, [ { "node":"RSS Read", "type":"main", "index":0 } ] ] }, "RSS Read":{ "main":[ [ { "node":"Loop Over Items", "type":"main", "index":0 } ] ] } }, "pinData":{} }


---|---