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 才是应该先建立的习惯。

开始前:先把上一期的资料卡准备好
新建一个工作流,添加 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

第 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 的表达式,最后一句话会自动显示新任务。

第 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,能减少不必要的名称依赖。

最关键的一次验证:只改一处,三处内容都应该跟着变
回到“准备资料卡”,只修改两个字段的值:
| 字段名 | 新值 |
|---|---|
name |
qilinora |
task |
发布本周文章 |
现在从 Manual Trigger 重新执行整条工作流,并按顺序检查三个地方:
- “准备资料卡”的 OUTPUT 中,
task已变成发布本周文章。 - “生成动态提醒”的 OUTPUT 中,
message已变成你好,qilinora。今天要完成:发布本周文章。。 - “明确引用原始任务”的 OUTPUT 中,
originalTask也显示发布本周文章。
这次验证的重点不是让三个地方都出现相同句子,而是确认它们都在读取同一份来源数据。以后你接入表单、Notion、RSS 或 API 时,只要上游资料卡变了,正确写好的表达式就会自然跟着变化。

常用表达式先只记住这 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 重跑整条流程,确认上游资料卡已经是新值。 |

你现在真正掌握的,不是几串符号
表达式最容易让人误以为“我要开始写代码了”。但对大多数 n8n 工作流来说,它更像是给固定模板留出几个会自动填充的空格。
你现在已经可以用四句话判断自己该怎么写:
| 你要问的问题 | 你的答案 |
|---|---|
| 当前节点要用的数据在哪里? | 先看当前节点的 INPUT。 |
| 数据已经在 INPUT 里吗? | 在,就先用 $json.字段名。 |
| 数据不在 INPUT,但我知道它来自哪个节点吗? | 知道,再用 $('<节点名称>').item.json.字段名。 |
| 为什么结果不对? | 从上游资料卡开始,一站一站看 INPUT 与 OUTPUT。 |
表达式不是凭空制造内容,它只是让下一个节点准确地拿到上一个节点已经准备好的内容。
当你养成“先看资料卡,再拖字段”的习惯后,后面不管是给飞书消息填标题、给 Notion 页面写属性,还是把 API 返回的数据整理成报告,做法都不会变得陌生。
下一篇预告
现在你的工作流已经会把资料卡里的内容取出来了。但不是每一张资料卡都应该走同一条路:任务有时需要提醒,有时应该先归档;内容有时该发布,有时应该停下来人工确认。
下一篇我们会让工作流第一次学会“选择”:
n8n 的 IF 和 Switch 怎么选:让工作流真正会判断。
我们会继续使用 qilinora 的任务资料卡,比较只有两个出口的 IF,和需要多条出口的 Switch;并且用最小练习让你看懂一张资料卡为什么会走向不同分支。
参考资料
[1]n8n Docs:Reference previous nodes