NocoBase RunJS 深度解析:ctx.collection 数据表实例的元数据访问、主键操作与字段联动实践
2026/9/17 13:04:24 网站建设 项目流程

NocoBase RunJS 深度解析:ctx.collection 数据表实例的元数据访问、主键操作与字段联动实践

【免费下载链接】nocobaseNocoBase is an open-source AI + no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase

ctx.collection是 NocoBase RunJS 运行时中最核心的上下文属性之一,它指向当前 JS 执行上下文关联的数据表(Collection)实例,让开发者无需硬编码表名,就能在运行时动态读取数据表的名称、字段列表、主键(filterTargetKey)、数据源归属与模板类型等元数据。本文基于 官方 ctx.collection 文档,结合 NocoBase 仓库中 RunJS 上下文的实际实现,完整讲解其适用场景、属性方法清单、与ctx.collectionField/ctx.blockModel的关系,以及三个可直接复制的实战示例(打开弹窗传filterByTk、遍历字段做必填校验、获取关联字段构建子表格),读完即可在自己的 JS 区块 / JS 字段中正确使用这一对象。

一、它是什么:上下文关联的数据表实例

在 NocoBase 中,界面(区块)和字段都建立在"数据表(Collection)"之上。当你在 JS 区块(JSBlock)、JS 字段(JSField)、表格列(JSColumn)等场景中编写 RunJS 代码时,运行时会把当前上下文绑定的 Collection 实例注入为ctx.collection。它的典型来源是ctx.blockModel.collection(父区块绑定的数据表)或ctx.collectionField?.collection(当前字段所属的数据表)。

从源码结构看,RunJS 上下文的定义位于 flow-engine 包的 runjs-context 目录中,例如 JSFieldRunJSContext.ts 与 JSColumnRunJSContext.ts 都显式声明了collection属性,并注明其为"集合定义元数据(只读,描述字段所属集合的 Schema)"。也就是说,ctx.collection是一份只读的元数据视图——适合读取结构信息,而不是用来直接执行数据库增删改(那属于ctx.resource/ API 的范畴)。

// 类型定义 collection: Collection | null | undefined;

需要特别注意空值:在数据区块、表单区块、表格区块等"绑定数据表"的场景下它通常可用;但独立 JSBlock 若未绑定数据表,ctx.collection可能为nullundefined,使用前建议做空值判断(下文示例均采用?.访问)。

二、适用场景速查

场景说明
JSBlock区块绑定的数据表,可访问namegetFieldsfilterTargetKey
JSField / JSItem / JSColumn当前字段所属数据表(或父区块数据表),用于获取字段列表、主键等
表格列 / 详情区块根据数据表结构渲染、打开弹窗时传入filterByTk

一个容易踩坑的点:在子表格、关联字段等场景中,ctx.collection可能指向的是关联目标数据表(子表),而不是父区块绑定的数据表,此时它与ctx.blockModel.collection并不相同。

三、常用属性详解

属性类型说明
namestring数据表名称(如usersorders),常用于动态拼接 API 资源名
titlestring数据表标题(含国际化)
filterTargetKeystring \| string[]主键字段名,用于filterByTkgetFilterByTK
dataSourceKeystring数据源 key(如main),可据此判断数据表属于主数据源还是外部数据源
dataSourceDataSource所属数据源实例
templatestring数据表模板(如generalfiletree),可用于区分普通表、文件表、树形表
titleableFieldsCollectionField[]可作为标题展示的字段列表
titleCollectionFieldCollectionField标题字段实例

这些属性在动态场景下尤其有用。例如借助name可以写出"与表名解耦"的代码:

// 用数据表名称动态请求资源,避免硬编码 const res = await ctx.resource[ctx.collection.name].get({ filterByTk: ctx.record?.[ctx.collection.filterTargetKey], });

借助template可以针对不同形态的表采取不同渲染策略(如树形表与普通表);借助titleableFields/titleCollectionField可以动态决定"记录标题"用哪个字段展示。

四、常用方法详解

方法说明
getFields(): CollectionField[]获取全部字段(含继承),用于遍历字段做校验、联动、渲染
getField(name: string): CollectionField \| undefined按字段名获取单个字段
getFieldByPath(path: string): CollectionField \| undefined按路径获取字段(支持关联,如user.name
getAssociationFields(types?): CollectionField[]获取关联字段,types可为['one']['many']
getFilterByTK(record): any从记录中提取主键值,用于 API 的filterByTk

几点关键行为:

  • getFields()的继承合并规则:它会合并继承数据表的字段,且自身字段覆盖同名的继承字段,因此拿到的字段列表就是当前数据表"最终生效"的完整结构。
  • getFilterByTK(record)filterTargetKey的配套方法,等价于"从一条记录中取出主键值",在需要批量构造filterByTk参数时比手动取字段更稳。
  • getFieldByPath支持关联路径(如user.name),适合需要跨表读取字段定义的联动逻辑。

五、与 ctx.collectionField、ctx.blockModel 的关系

三者经常配合使用,按"想要什么"选择正确的入口:

需求推荐用法
当前上下文关联的数据表ctx.collection(等价于ctx.blockModel?.collectionctx.collectionField?.collection
当前字段的数据表定义ctx.collectionField?.collection(字段所属数据表)
关联目标数据表ctx.collectionField?.targetCollection(关联字段的目标数据表)

也就是说:在普通表单 / 表格中,ctx.collection通常就是区块绑定的数据表;而在子表格等嵌套场景中,它更可能"下沉"为当前字段所在的那张表。当需要区分"父表"和"当前表"时,优先显式使用ctx.blockModel.collectionctx.collectionField?.targetCollection,语义更清晰。

相关文档可继续阅读 ctx.collectionField、ctx.blockModel、ctx.model。

六、实战示例

6.1 获取主键并打开弹窗

打开记录详情 / 编辑弹窗时,filterByTk参数需要的是主键值。用filterTargetKey取主键字段名(回退'id'),可以兼容自定义主键的表。仓库中表格单元格打开弹窗的场景片段(cell-open-dialog.snippet.ts)也是围绕这一模式组织的:

const primaryKey = ctx.collection?.filterTargetKey ?? 'id'; await ctx.openView(popupUid, { mode: 'dialog', params: { filterByTk: ctx.record?.[primaryKey], record: ctx.record, }, });

6.2 遍历字段做必填校验或联动

利用getFields()拿到完整字段列表,再结合ctx.form逐字段取当前值,即可实现"不写死字段名"的动态必填校验:

const fields = ctx.collection?.getFields() ?? []; const requiredFields = fields.filter((f) => f.options?.required); for (const f of requiredFields) { const v = ctx.form?.getFieldValue(f.name); if (v == null || v === '') { ctx.message.warning(`${f.title} 为必填`); return; } }

同样的遍历模式也可以用来做字段联动(例如根据f.options中的配置判断某字段是否应禁用)。

6.3 获取关联字段构建子表格

getAssociationFields(types)支持按关联类型过滤,传入['many']可只拿到一对多关联字段,用于自动发现"这张表有哪些子表可挂载":

const oneToMany = ctx.collection?.getAssociationFields(['many']) ?? []; // 用于构建子表格、关联资源等

七、注意事项

  • filterTargetKey是数据表的主键字段名;部分数据表可能为string[]复合主键;未配置时常用'id'作为回退。
  • 子表格、关联字段等场景,ctx.collection可能指向关联目标数据表,与ctx.blockModel.collection不同,注意区分"当前表"与"父表"。
  • getFields()会合并继承数据表的字段,自身字段覆盖同名继承字段。
  • ctx.collection为只读的 Schema 元数据视图,且独立 JSBlock 未绑表时可能为null,建议统一使用?.与回退值访问。

八、小结

ctx.collection是 NocoBase RunJS 中"让代码认识数据表结构"的入口:name/filterTargetKey/template等属性解决"这是哪张表、主键是谁",getFields/getFieldByPath/getAssociationFields等方法解决"它有哪些字段、如何遍历联动"。配合ctx.formctx.resourcectx.openView等上下文能力,即可写出与具体表名解耦、可复用于多张数据表的通用 JS 逻辑。其定义可追溯至 JSFieldRunJSContext.ts 等 runjs-context 上下文实现,相关行为亦有 flow-engine 包的 RunJS 上下文测试(如 runjsContext.test.ts)覆盖。

【免费下载链接】nocobaseNocoBase is an open-source AI + no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询