mcpField
N
n8n-data-tables-official

n8n-data-tables-official

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

关于 n8n-data-tables-official

面向 n8n 工作流设计者,介绍内置 Data Tables 的表结构、操作方式和设计规范,适用于小到中等规模的持久化状态。涵盖查找表、事件记录和按行逻辑去重,并说明何时应改用真实数据库。

主要功能

  1. 01通过列和行存储持久化数据
  2. 02支持插入、更新、查询与删除
  3. 03提供 upsert 和行存在性判断
  4. 04说明去重与查找表模式
  5. 05涵盖列类型及关联设计

适用场景

  1. 01保存稳定的查找数据
  2. 02记录近期事件或审计信息
  3. 03需要检查或查询的去重状态
  4. 04在工作流中维护父子数据关系

MCP 相关

介绍 n8n Data Tables 的 data-table MCP 工具,可供 MCP 客户端操作表数据。

安装

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

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

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

包含的文件

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

references/
DEDUP_PATTERNS.md
OPERATIONS.md
SCHEMA_DESIGN.md

详细介绍

n8n Data Tables

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

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

必须遵守的规则

  1. 系统管理的列 + 外部 ID。 每张表都会自动包含 3 列: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-official 中也指出了同样的 Set 节点反模式。)

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

  • 创建或更新后,通过 get_workflow_details 验证 columns 参数。 UI 在手动映射模式下有显示问题(会显示“Currently no items exist”,但实际上没有数据丢失)。检查 JSON 可以确认已持久化的内容。

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

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

默认列

无论是否声明,每张 Data Table 都包含以下列:

列类型行为
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”界面显示问题

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

常见模式

按外部 ID 去重

对于简单的“我是否见过这个值?”去重,默认使用 Remove Duplicates 节点(“items seen in previous executions”模式)。这是只需一个节点的解决方案,使用内部存储,无需维护架构。只有在有理由让去重状态存放在真实表中时,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 界面编辑,工作流在执行时读取:

[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-official。关于 Merge 汇合和形状相同的分支,请参阅 n8n-node-configuration-official 中的 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-official 和 n8n-node-configuration-official 的 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 检查实际的 Data Table 内容,或执行后续 Get,确认各列没有被静默写入 NULL。

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

评论

支持 Markdown