mcpField
N
n8n-data-tables

n8n-data-tables

github.com/n8n-io数据与数据库558354 次安装2 周前更新
代码仓库

关于 n8n-data-tables

n8n-data-tables 是面向 Agent 的技能,介绍如何使用 n8n 内置表格存储保存工作流状态,并说明表结构设计、CRUD 操作及其在查找、去重和事件记录中的适用场景。

主要功能

  1. 01用于持久状态的表格存储
  2. 02CRUD 操作指南
  3. 03表结构与列设计
  4. 04查找、去重和事件记录模式
  5. 05发布前验证 Data Table

适用场景

  1. 01为工作流保存查找数据
  2. 02跟踪去重或幂等状态
  3. 03记录并查询近期事件

MCP 相关

该技能介绍用于创建和操作表格的 Data Table MCP 工具及 n8n `dataTable` 节点。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/n8n-io/skills --skill n8n-data-tables

安装后在 Claude Code 中输入/n8n-data-tables确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
DEDUP_PATTERNS.md
OPERATIONS.md
SCHEMA_DESIGN.md

详细介绍

n8n 数据表

数据表是 n8n 内置的表格存储:位于 n8n 实例内的真实表格,包含列、类型和行,并可通过 dataTable 节点和数据表 MCP 工具执行 CRUD 操作。

可用它们存储本地持久状态:查找表、近期事件、每个会话的库存、计数器、幂等性跟踪,以及在需要逐行逻辑或外部可见性时使用的去重状态(单纯判断“是否见过这个值?”的去重应使用 Remove Duplicates 节点)。适用于中小规模数据量(数万行没问题,数百万行则应使用真正的数据库)。

不可妥协的规则

  1. 系统管理的列 + 外部 ID。 每张表都会自动包含三个列:id(bigserial)、createdAt、updatedAt。不要在 create_data_table 中声明它们(否则会报错或遮蔽系统列)。插入时不要写入这些列。对于来自外部的领域标识符(arxivId、stripeCustomerId、requestId),应添加单独的列,并据此执行去重和查找。
  2. 列中只存基本类型,嵌套数据使用 string + _object 后缀。 不存在 JSON/object/array 列类型。对于嵌套数据(数组、已解析的对象),使用 string 列,写入时调用 JSON.stringify(...),读取时调用 JSON.parse(...)。为列名添加 _object 标记(例如 keyInsights_object)。该后缀是约定,告知读取方需要解析。参见 references/SCHEMA_DESIGN.md。

强烈建议的默认做法

  • 不要在 Data Table 节点前添加 Set 节点来修改字段。 Data Table 节点的逐列表达式槽与 Set 字段功能一样强大,因此 Set 节点并没有完成任何 Data Table 节点无法自行完成的工作。(n8n-expressions 中也指出了相同的 Set 节点反模式。)

  • 列名大小写遵循 n8n 的规范:camelCase。 自动管理的列采用 camelCase(createdAt、updatedAt),因此用户列采用相同风格更清晰:arxivId、paperId、taxRate。在同一查询中混用大小写(createdAt >= ... AND arxiv_id eq ...)看起来像拼写错误。字符串化数据块列无论如何都应保留 _object 后缀(keyInsights_object),下划线是约定标记,而非大小写风格。

  • 创建或更新后,通过 get_workflow_details 验证 columns 参数。 UI 在手动映射模式下有显示问题(显示“目前不存在任何项目”,但实际数据并未丢失)。检查 JSON 可确认哪些内容已持久化。

  • 数据结构适合时,可以使用关系型设计。 对于真正的父子数据(论文 → 摘要、客户 → 订单),通过 id 引用父记录,明确命名列(paperId、customerId),并在工作流逻辑中确保完整性。对于无需建模关系的扁平场景(去重、查找、审计),不要强行使用关系型设计。

  • 存储格式不等于接口格式。 从子工作流返回 _object 字段之前,应先解析它们。调用方不应收到还需要自行解析的字符串化内容。参见 references/SCHEMA_DESIGN.md 中的“存储格式 ≠ 接口格式”。

默认列

每张数据表都包含以下列,无论你是否声明:

列类型行为
idbigserial / number自动递增的主键。n8n 会在插入时分配,且不能写入该列。会在插入响应中返回。
createdAttimestamp插入时自动设置。
updatedAttimestamp每次更新时自动刷新。

实际使用时:

  • 不要在 create_data_table 中声明它们。它们已经存在。
  • 在查询中使用它们,无需创建自己的时间戳列。“今天创建”:createdAt >= '<today ISO>'。“自上次同步以来更新”:updatedAt >= $('Last Sync').item.json.timestamp。
  • 不要将它们用作跨系统标识符。 自动生成的 id 是内部标识符,在重建表或迁移实例时会重置。领域标识符应使用自定义列。

适合时采用关系型设计

Data Tables 不强制执行外键,但如果数据确实具有父子结构,你仍然可以跨表建模。需要注意的是:完整性由你负责,而不是由 n8n 负责。

  • 通过 id 引用父行。 子表在某一列中保存父行的 id。
  • 在列名中说明引用关系。 paperId、customerId、eventId 可以让关系一目了然。
  • 在工作流逻辑中确保完整性。 插入子行前,先查找父行。删除父行前,决定如何处理子行(删除、保留孤立行或归档)。n8n 不会级联处理。
  • 留意过期引用。 指向已删除父行的子行会造成不易察觉的错误。可以软删除,或运行清理工作流。

对于复杂的关系结构(涉及 3 张或更多表并需要联接、事务性写入),应使用真正的 SQL 数据库。

操作:分别适用于哪些场景

操作适用场景
insert始终新增。创建新行,n8n 会分配 id。
upsert“不存在则新增,存在则更新。”需要设置 matchType 和筛选条件,以判断记录是否存在。
update“修改符合此筛选条件的行。”无匹配项时不会插入。
get获取符合筛选条件的行(返回 0 个或多个)。支持 orderBy、limit、returnAll。
deleteRows删除符合筛选条件的行。
rowExists / rowNotExists针对传入项的布尔式筛选。常用于去重分支判断。

如需了解完整的操作范围(筛选语法、matchType、排序模式),请参阅 references/OPERATIONS.md。

“Currently no items exist” UI 显示问题

当 SDK 保存手动模式的列映射(mappingMode: 'defineBelow')时,即使运行时能正确持久化数据,n8n UI 的 “Values to insert” 面板也可能显示为空(“Currently no items exist”)。如果用户反馈 Insert 节点“看起来坏了”或“没有字段”,请告知他们这是 UI 显示问题:点击列参数上的重新加载(刷新)按钮,即可重新填充架构并显示映射。不会丢失数据,可随时操作。

常见模式

按外部 ID 去重

对于简单的“是否见过这个值?”去重,默认使用 Remove Duplicates 节点的“之前执行中见过的项目”模式。它只需一个节点,使用内部存储,无需维护架构。只有在有理由让去重状态存放在真实表中时,才应使用 Data Tables:

  • 需要查询或检查去重状态。 例如仪表板、审计,或“过去一周处理过哪些项目?”
  • 命中时需要行级逻辑。 例如按类别设置 TTL(“类别 A 在 30 天后过期,类别 B 在 7 天后过期”)、根据已存状态决定是否重新处理,或根据状态列进行分支。
  • 需要按租户或用户进行命名空间隔离, 而 Remove Duplicates 的历史记录存储无法表达这种需求。

满足上述条件时:

[Source: { arxivId, ... }]
   ↓
[Data Table Get: filter arxivId eq $json.arxivId, limit 1]
   ↓
[IF: result has items?]
   ├── Yes → [Skip, or apply row-level logic from the stored row]
   └── No  → [Process] → [Data Table Insert: { arxivId, ...rest }]

如需了解完整的模式范围(upsert、rowNotExists、Get+IF、幂等键),请参阅 references/DEDUP_PATTERNS.md。

查找表

稳定的参考数据(国家 → 税率、套餐 → 功能标志)。通过 n8n UI 编辑,工作流在执行时读取:

[Data Table Get: filter country eq $json.country, limit 1]
   ↓
[Use the looked-up row's taxRate, etc.]
最近事件 / 审计跟踪

仅追加插入,之后再查询:

[Workflow event] → [Data Table Insert: { userId, eventType, payloadSummary }]

有了 createdAt,无需自行处理时间戳,就能轻松查询“最近一小时内的事件”。

参考文件

文件何时阅读
references/SCHEMA_DESIGN.md设计列和类型、了解无外键的关系型模式、映射模式(defineBelow 与 autoMapInputData),以及 Data Tables 不适用的场景
references/OPERATIONS.md操作范围(insert/upsert/update/get/delete/rowExists)、筛选语法、matchType、orderBy
references/DEDUP_PATTERNS.md幂等键、RemoveDuplicates 节点与 Data Table 去重、先搜索再插入与 upsert

有关表达式规范($json 与 $('Node Name').item.json、Set 节点反模式),请参阅 n8n-expressions。有关 Merge 汇聚和同形分支,请参阅 n8n-node-configuration 的 references/MERGE_NODE.md。

反模式

反模式问题所在修复方法
在 Insert 前设置 Set 节点“来调整输入形状”平白多出一个节点,属于典型的 Set 反模式;添加列后,字段形状会发生偏移直接在 Insert 节点的各列映射槽中进行映射,或者重命名上游字段以启用自动映射
在 create_data_table 中声明 id、createdAt、updatedAt会报错,或者用用户列覆盖系统列,导致系统列无法自动更新不要声明这些列,它们已经存在
在 Data Tables 中存储应用的关键数据如果 n8n 出故障,你将无法访问这些数据无法承受丢失的数据应存储在真正的数据库中
在 Data Tables 中存储跨应用的权威数据难以与非 n8n 使用方共享,查询方式也不方便使用真正的数据库
将自动生成的 id 视为跨实例稳定标识符表重新创建后会重置,无法移植使用领域 ID 列(arxivId、requestId)来进行跨系统引用
假设外键会级联删除n8n 不会级联删除,删除父项后会留下孤立的子项使用软删除,或运行维护引用完整性的清理工作流
引用紧邻前一个节点,但中间节点剥离了 json对于“本应存在”的字段,Insert 会静默写入 NULL按名称引用稳定的上游节点,或使用 NoOp/Merge 汇聚锚点(参见 n8n-expressions 和 n8n-node-configuration 中的 references/MERGE_NODE.md)
手动映射模式 + Set 节点来修复“Currently no items exist”这并不能解决任何问题,只是 UI 的小问题;你添加了一个无用的 Set 节点通过 get_workflow_details 确认 columns.value 包含你的映射;运行时没有问题。告诉用户按下列参数上的重新加载按钮,让 UI 显示这些字段。

发布前验证

创建或更新使用 Data Tables 的工作流后:

  1. validate_workflow 验证通过。
  2. 使用 get_workflow_details 检查每个 Data Table 节点的 columns。value 和(手动映射时的)schema 均已填充。
  3. 使用固定数据运行 test_workflow。Insert 响应应包含 id、createdAt、updatedAt。
  4. 通过 UI 或后续的 Get 操作检查实际的 Data Table 内容,确认各列没有被静默写入 NULL。

第 4 步尤其重要,特别是首次连接新的 Insert 时。剥离上下文的中间节点 + 手动映射 + UI 小问题,会导致列被静默写入 NULL。

评论

支持 Markdown