n8n 的表达式怎么写:让下一个节点自动拿到上一节点的数据

n8n 的表达式怎么写:让下一个节点自动拿到上一节点的数据
节点实战系列第 03 篇: 上一篇我们把 JSON 看成会在节点之间传递的资料卡。这一篇继续做同一条工作流:不再手抄资料卡里的内容,而是让下一个节点自己把需要的栏目拿出来。

你已经知道,上一节点可以交出一张这样的资料卡:

{
  "name": "qilinora",
  "task": "整理本周阅读清单"
}

可当你到了下一个节点,想生成一句提醒时,最容易做的事情还是手动输入:

你好,qilinora。今天要完成:整理本周阅读清单。

这句话当然能显示出来,但它没有自动化。下次资料卡里的任务变成“发布本周文章”,你还得回到这个节点,把整句话重新改一遍。数据明明已经在上一站准备好了,却没有真正参与后面的流程。

表达式就是为了解决这件事。

一句话结论: 表达式不是让你在 n8n 里写复杂程序;它只是告诉当前节点:不要把这里当成固定文字,请去输入资料卡里读取某个栏目。

今天我们只完成一条很小、但以后会反复复用的能力:让 n8n 从上一步的资料卡中读取 name 与 task,自动组合成一条动态提醒。你不需要 Webhook、API Key、飞书账号或代码节点;只需要上一期已经学过的 Manual Trigger 与 Edit Fields (Set)。


先看你最终会得到什么

完成后,你的流程仍然很短:

Manual Trigger
      ↓
准备资料卡
      ↓
生成动态提醒

第一步会准备下面这张资料卡:

{
  "name": "qilinora",
  "task": "整理本周阅读清单"
}

第二步不会重新手打 qilinora 和任务名称,而是通过表达式读取上一张资料卡,生成:

{
  "message": "你好,qilinora。今天要完成:整理本周阅读清单。"
}

更重要的是:当你只修改前一节点中的 task,最后的 message 会自动跟着变。

节点 它像资料流里的什么岗位 本篇让它完成什么
Manual Trigger 启动按钮 开始一次安全的手动练习。
准备资料卡 资料录入岗 写入 name 与 task 两个字段。
生成动态提醒 文书整理岗 从输入资料卡读取字段,组合出 message。
最小工作流:手动触发、准备资料卡与生成动态提醒

表达式到底在做什么?先把它想成“自动填表格”

假设你在整理一封提醒信。信的格式每次都一样:

你好,____。今天要完成:____。

以前你要手动填写两个空格。表达式做的事情,是告诉 n8n:第一个空格去资料卡里找 name,第二个空格去资料卡里找 task。

所以,表达式最重要的不是那些符号,而是这句心里话:

这里的内容不是写死的;它要跟着每一次输入资料卡变化。
你看到的写法 用自动填表理解 它实际在读取什么
{{ $json.name }} 把资料卡中“姓名”一栏填进当前位置。 当前输入资料卡的 name 字段。
{{ $json.task }} 把资料卡中“任务”一栏填进当前位置。 当前输入资料卡的 task 字段。
{{ $('准备资料卡').item.json.task }} 直接回到名为“准备资料卡”的档案柜,取出对应资料卡的任务。 指定前序节点中与当前 item 关联的 task 字段。

n8n 官方将 $json 定义为当前节点正在处理的输入 item 的 JSON 数据的简写;当你需要明确引用某个前序节点时,可以使用 $('<节点名称>').item.json。1

什么时候先用 $json,什么时候才写前序节点名称?

刚开始时,请优先用 $json。

因为当前节点的 INPUT 本来就是上一节点交给它的资料卡。只要你要的内容就在 INPUT 里,{{ $json.name }} 最短、最好读,也最不容易因为节点改名而失效。

只有当流程走到后面,当前 INPUT 已经被其他节点改得看不出原始字段,或者你确实需要从某个指定节点取一项旧数据时,才使用:

{{ $('准备资料卡').item.json.task }}

本篇会让你两种都看见,但第一种 $json 才是应该先建立的习惯。

表达式就像自动填表:用 name 与 task 自动填入固定提醒模板

开始前:先把上一期的资料卡准备好

新建一个工作流,添加 Manual Trigger。然后添加 Edit Fields (Set) 节点,并把它重命名为:

准备资料卡

在这个节点中新增两个文本字段:

字段名 类型 值
name String / 文本 qilinora
task String / 文本 整理本周阅读清单

执行一次工作流,然后打开“准备资料卡”的 OUTPUT。请先确认你看到的是:

{
  "name": "qilinora",
  "task": "整理本周阅读清单"
}

这一步在做什么? 它不是表达式练习本身,而是在把可被下一节点读取的资料放好。表达式不能从空气里取值;它必须先有一张已经到达当前流程的资料卡。

成功标志: name 与 task 都出现在 OUTPUT 中,且值完全正确。

如果和教程不同: 如果你在 OUTPUT 中没有看到两个字段,先检查字段是否保存、节点是否执行成功;不要先去处理后面的表达式。


第 1 步:先让 n8n 帮你生成表达式,不要急着手敲

在“准备资料卡”后添加第二个 Edit Fields (Set) 节点,重命名为:

生成动态提醒

在这个节点中新建一个字段:

字段名 类型
message String / 文本

此时先不要在值里输入 qilinora。打开当前节点的 INPUT 面板,你应该会看见来自上一节点的 name 与 task。

接着,点击 message 的值输入框,切换到 Expression 模式。不同版本可能将入口显示为齿轮图标、fx、Expression 或“添加表达式”;只要输入框进入可计算模式即可。

然后把 INPUT 中的 name 字段拖进表达式编辑区。n8n 会生成类似下面的写法:

{{ $json.name }}

现在先执行一次“生成动态提醒”节点。它的 OUTPUT 应为:

{
  "message": "qilinora"
}

这一步在做什么? 你没有把 qilinora 写进 message;你告诉 n8n:每次运行时,都从当前输入资料卡的 name 栏目中取值。官方文档说明,表达式模式可以通过将 INPUT 面板中的值拖入字段来建立,拖放的数据映射会生成对应字段路径。2

成功标志: OUTPUT 中的 message 显示为 qilinora,而不是 {{ $json.name }} 这一串原始文字。

如果和教程不同: 如果你看不到 name,请先执行“准备资料卡”,再回到当前节点;前置节点没有执行时,n8n 无法为表达式提供可读取的数据。2

第 1 步:从 INPUT 面板拖入 name 字段到 Expression

第 2 步:把固定文字和动态字段组合成一句提醒

现在你已经能取到一个字段了。接下来不需要新建节点,继续编辑 message 的值。

如果你的编辑器支持在文本中穿插表达式,可以将它写为:

你好,{{ $json.name }}。今天要完成:{{ $json.task }}。

如果你的编辑器要求整个字段都使用 Expression 模式,请写成一条完整表达式:

{{ '你好,' + $json.name + '。今天要完成:' + $json.task + '。' }}

再次执行“生成动态提醒”。现在你应该看到:

{
  "message": "你好,qilinora。今天要完成:整理本周阅读清单。"
}

这一步在做什么? 固定文字像提醒信的模板;$json.name 与 $json.task 是每次从当前资料卡中自动填入的空格。n8n 会在每次 execution 中按照当前数据计算表达式,因此不同资料卡会得到不同结果。2

message 中的部分 它来自哪里 下次运行会不会自动变化
你好, 你写好的固定模板。 不会。
$json.name 当前输入资料卡的 name。 会。
。今天要完成: 你写好的固定模板。 不会。
$json.task 当前输入资料卡的 task。 会。

成功标志: 你修改上一节点的 task 后,不需要触碰 message 的表达式,最后一句话会自动显示新任务。

第 2 步:固定文字与动态字段共同组成一条完整提醒

第 3 步:只在需要时,直接引用指定的前序节点

到目前为止,$json 已经够用。因为“生成动态提醒”的 INPUT 就是“准备资料卡”的 OUTPUT。

但以后流程会变长:中间可能经过日期格式化、内容清洗、AI 摘要或其他节点。某个节点也许不再把原始 task 继续传下来,这时你需要明确告诉 n8n:请回到哪个节点取哪一项资料。

为了练习这个写法,在“生成动态提醒”后再添加一个 Edit Fields (Set) 节点,重命名为:

明确引用原始任务

新建字段:

字段名 表达式
originalTask {{ $('准备资料卡').item.json.task }}

执行这个节点。你应该看到:

{
  "originalTask": "整理本周阅读清单"
}

这一步在做什么? $('准备资料卡') 指向你命名为“准备资料卡”的节点;.item.json.task 则表示取出与当前资料卡关联的 item 中的 task 字段。它不是一种更高级、更应该优先使用的写法,而是一种在流程变长后帮助你回溯来源的明确写法。1

成功标志: originalTask 与最初 task 的内容一致,即使中间节点只留下了 message,它仍能正确找到原始任务。

非常重要: 节点名称必须和画布上的名称完全一致。如果你后来把“准备资料卡”改名,表达式中的节点名称也需要同步调整。刚开始时优先用 $json,能减少不必要的名称依赖。

第 3 步:数据在当前 INPUT 时优先使用 $json,缺失时再回看指定前序节点

最关键的一次验证:只改一处,三处内容都应该跟着变

回到“准备资料卡”,只修改两个字段的值:

字段名 新值
name qilinora
task 发布本周文章

现在从 Manual Trigger 重新执行整条工作流,并按顺序检查三个地方:

  1. “准备资料卡”的 OUTPUT 中,task 已变成 发布本周文章。
  2. “生成动态提醒”的 OUTPUT 中,message 已变成 你好,qilinora。今天要完成:发布本周文章。。
  3. “明确引用原始任务”的 OUTPUT 中,originalTask 也显示 发布本周文章。

这次验证的重点不是让三个地方都出现相同句子,而是确认它们都在读取同一份来源数据。以后你接入表单、Notion、RSS 或 API 时,只要上游资料卡变了,正确写好的表达式就会自然跟着变化。

最关键验证:修改上游 task 后,message 与 originalTask 会同步更新

常用表达式先只记住这 4 种

表达式功能很强,但现在不需要记住几十种写法。下面四种已经足够覆盖本系列接下来几篇文章的大多数需要。

你想做什么 推荐写法 什么时候用
读取当前资料卡的一个字段 {{ $json.name }} 当前 INPUT 已包含这个字段。
读取当前资料卡中的嵌套字段 {{ $json.author.name }} 字段藏在另一层资料卡中。
明确读取某个前序节点的关联资料 {{ $('准备资料卡').item.json.task }} 当前 INPUT 没有原始字段,但前序节点有。
在空值时给出替代内容 {{ $ifEmpty($json.task, '暂未填写任务') }} 某些资料卡可能没有该字段。

$ifEmpty() 是 n8n 表达式参考中提供的辅助函数之一:当第一个值为空时,它会返回你设置的替代值。3 但在刚开始学习时,不要因为“可能为空”就把所有字段都塞满复杂逻辑;先在 INPUT 中确认数据形状,再决定是否真的需要它。


跟教程不同怎么办:按这个顺序排查

你看到的情况 不要急着做什么 应该先做什么
message 显示 {{ $json.name }} 原始文字 不要重新创建整个节点。 检查字段是否已切换到 Expression 模式。
message 显示空白或 undefined 不要先把值写死成 qilinora。 打开当前节点 INPUT,确认 name 或 task 是否真的存在,拼写和大小写是否一致。
拖不进字段,或 INPUT 面板没有数据 不要猜字段路径。 从 Manual Trigger 重新执行到上一步;先让前序节点交出资料卡。
提示 Referenced node is unexecuted 不要反复点击最后一个节点。 先执行被引用节点,或检查连线是否保证该节点会在本次流程中运行。2
明确引用前序节点后报错 不要随意增加引号和括号。 检查节点名称是否完全一致;表达式中的节点名包括中文、空格和标点都必须对应。
JSON 模式提示不是合法 JSON 不要在 JSON 对象里混入未处理的普通文字。 先确认 JSON 的花括号、逗号与引号正确;字段可能为空时先检查 INPUT。2
一次运行正确,下一次却内容没变 不要只执行最后一个节点。 从 Manual Trigger 重跑整条流程,确认上游资料卡已经是新值。
表达式排错顺序:先确认字段在 INPUT 中,再确认 Expression 模式,最后检查前序节点是否已执行

你现在真正掌握的,不是几串符号

表达式最容易让人误以为“我要开始写代码了”。但对大多数 n8n 工作流来说,它更像是给固定模板留出几个会自动填充的空格。

你现在已经可以用四句话判断自己该怎么写:

你要问的问题 你的答案
当前节点要用的数据在哪里? 先看当前节点的 INPUT。
数据已经在 INPUT 里吗? 在,就先用 $json.字段名。
数据不在 INPUT,但我知道它来自哪个节点吗? 知道,再用 $('<节点名称>').item.json.字段名。
为什么结果不对? 从上游资料卡开始,一站一站看 INPUT 与 OUTPUT。
表达式不是凭空制造内容,它只是让下一个节点准确地拿到上一个节点已经准备好的内容。

当你养成“先看资料卡,再拖字段”的习惯后,后面不管是给飞书消息填标题、给 Notion 页面写属性,还是把 API 返回的数据整理成报告,做法都不会变得陌生。


下一篇预告

现在你的工作流已经会把资料卡里的内容取出来了。但不是每一张资料卡都应该走同一条路:任务有时需要提醒,有时应该先归档;内容有时该发布,有时应该停下来人工确认。

下一篇我们会让工作流第一次学会“选择”:

n8n 的 IF 和 Switch 怎么选:让工作流真正会判断。

我们会继续使用 qilinora 的任务资料卡,比较只有两个出口的 IF,和需要多条出口的 Switch;并且用最小练习让你看懂一张资料卡为什么会走向不同分支。


参考资料

[1]n8n Docs:Reference previous nodes

[2] n8n Docs:Expressions for data transformation

[3] n8n Docs:Expression reference