graphql-engine 的 NoSQL Schema Sampling RFC基于 MongoDB 采样的自动 Schema 生成方案【免费下载链接】graphql-engineBlazing fast, instant realtime GraphQL APIs on all your data with fine grained access control, also trigger webhooks on database events.项目地址: https://gitcode.com/gh_mirrors/gr/graphql-engine导读本文围绕 Hasura graphql-engine 仓库中的 RFC 文档 rfcs/nosql-schema-sampling/readme.md 展开深入解析其提出的基于 NoSQL 采样自动生成 Schema方案如何利用mongosh Variety Node.js对 MongoDB 集合中的文档进行采样分析自动推导出字段形状与类型分布并生成可回写数据库的 JSON Schema 验证规则从而为 Hasura 的 GraphQL API 提供结构化的 schema 起点。读完本文你将掌握该 PoC 的完整运行方式、环境变量与采样定制方法并理解从文档采样到验证 schema 导出的底层实现链路。背景与问题NoSQL 的无模式与 GraphQL 的要结构Hasura 的数据库支持矩阵同时涵盖 SQL 与 NoSQL 两大类数据源。相比关系型数据库的强约束NoSQL 数据库如 MongoDB天然缺少预定义 schema——这带来了灵活性却也带来了一系列工程挑战RFC 将其归纳为五点固有的非结构化本质MongoDB 等 NoSQL 数据库没有预定义 schema数据管理、定义与演进都变得复杂GraphQL 需要结构作为护栏GraphQL 围绕 NoSQL 数据源引入的是无固定观点的护栏un-opinionated guardrails只有在获得类型安全与结构之后才能提升执行性能、提供可预测的 API 并改善编码体验上手易用性差缺少预定义 schema 使得新用户无法像接入 SQL 数据库那样即插即用式地把数据源接入 GraphQL导致 onboarding 流程复杂化校验 schema 使用率有限项目现有的一个解决方案是使用 MongoDB 自带的 validation schema但该方案并未被用户广泛采用功能对齐诉求让用户能够即时 introspection 并 track MongoDB 中的 Collections 与 Documents可以显著加速 Hasura 的 onboarding并让 NoSQL 数据库与 Hasura 支持的其他基于 schema 的数据库达到功能对齐feature parity。提案方案用采样推导 schema作为 GraphQL schema 的起点针对上述问题RFC 提出的核心方案是构建一个基于 NoSQL 采样技术的自动 schema 生成工具。其核心思路分三步采样Sampling对集合collection的全部文档或子集进行采样分析Analysis运行分析掌握文档集合universe of documents中出现的字段形状shapes与类型分布types生成Generation基于分析结果生成一个 schema作为 onboarding 起点用于支撑 Hasura 之上的 GraphQL schema。生成的 schema 具备可定制性终端用户可以根据需要调整。RFC 中给出的概念验证PoC针对 MongoDB 实现并明确指出同一套方法可以推广到其他 NoSQL 数据库后续也可以利用 Hasura 的 logical models 直接生成 Hasura 对 schema 的表示该点在 RFC 中以脚注形式标注为后续工作。开放问题方案落地前仍需回答的设计决策RFC 坦诚列出了数个尚未定论的开放问题这些决策直接决定了工具的形态选择器selectors需要哪些选择器来挑选合适的文档例如在 MongoDB 中可以选择基于查询条件query、最大深度max depth、集合百分比percentage of the collection或最大记录数max number of records来选择文档冲突类型的取舍当同一字段出现多种类型时工具应选择哪种类型例如某字段大部分是int、少量是string应取哪种是否需要做成可配置项可选嵌套对象的阈值编写 schema 时是否应提供类似字段必须在 x% 的文档中出现过must have been found in x % of documents的设置以过滤仅出现在极少数记录中的可选内嵌对象工具归属该能力应实现进核心工具还是保留灵活性作为外部工具集的一部分可复现性如何以对其他 NoSQL 数据库厂商可复现的方式实现这些开放问题在后文 PoC 的analyze.sh与 Variety 的配置参数中其实已经出现了初步的答案雏形例如 query/limit/maxDepth读者可以在实践中对照思考。概念验证PoC总体架构三件套流水线RFC 提供了一个可实际运行的 MongoDB schema sampler PoC存放在 rfcs/nosql-schema-sampling 目录下。它由三部分技术组合而成组件职责mongoshMongoDB 官方 Shell用于连接数据库、枚举集合、执行采样查询并驱动 Variety 脚本VarietyMongoDB schema 分析器仓库内为 schema_sampler/variety.js版本 1.5.1用于对集合文档做 key/type 统计Node.js运行 validation_exporter.js将 Variety 的分析结果转换为 MongoDB validation schema整个流水线由 schema_sampler/analyze.sh 编排枚举集合 → 逐个集合跑 Variety 采样分析 → 导出 validation schema JSON → 可选地将 schema 写回 MongoDB。生成的 validation schema 随后可以被 Hasura 用作 MongoDB 数据源之上的 GraphQL schema 生成基础。快速开始docker compose 一键运行PoC 使用 docker-compose.yml 定义了两个服务mongodbmongo:6镜像监听宿主机27017端口启动时通过 sample_data/import.sh 挂载到/docker-entrypoint-initdb.d/自动导入sample_mflix示例数据库内置 healthcheck每 5 秒对test库执行db.runCommand(ping).ok最长等待 10 秒、重试 5 次保证采样器在数据库就绪后才启动mongodb_samplernode镜像挂载./schema_sampler与./schema_exports两个卷command直接执行/schema_sampler/analyze.sh并通过depends_on: condition: service_healthy等待 MongoDB 健康。启动只需一条命令docker compose up启动后会自动完成加载sample_mflix示例数据库 → healthcheck 等待就绪 → sampler 运行archive.sh应为analyze.sh见下文源码说明完成集合 introspection、Variety 分析、validation schema 转换并回写 MongoDB。说明RFC 正文提到 sampler 运行/schema_sampler/archive.sh但仓库实际文件名为 schema_sampler/analyze.sh且 docker-compose 中command也指向analyze.sh——可以推断正文中的archive.sh为笔误实际入口以analyze.sh为准。sample_mflix示例数据位于 sample_data/sample_mflix包含movies.json约 2.3 万行、comments.json、theaters.json、users.json、sessions.json及loyalty-table.csv。从movies.json的示例文档可以看到其嵌套结构非常典型——顶层字段包含plot、genres数组、runtime、cast、awards嵌套对象、imdb嵌套对象含rating/votes/id、tomatoes多层嵌套等正是展示嵌套字段采样 类型冲突处理的绝佳素材。定制采样范围环境变量一览mongodb_sampler容器暴露了 5 个环境变量用于控制采样行为见 docker-compose.yml环境变量作用取值示例MONGO_DATABASEMongoDB 连接字符串指向目标数据库mongodb://root:passwordmongodb:27017/sample_mflixMONGO_USERNAMEMongoDB 用户名rootMONGO_PASSWORDMongoDB 密码passwordMONGO_SELECT_COLLECTIONS指定要分析采样的集合逗号分隔空表示全部集合、movies,commentsMONGO_UPDATE_COLLECTIONS是否将生成的 validation schema 自动写回集合true/false或留空视为 false在 analyze.sh 中可以看到这些变量的实际用法当MONGO_SELECT_COLLECTIONS为空时脚本通过mongosh ... --eval db.getCollectionNames()动态枚举全部集合并用tr -d [\[\]\ \n]清理输出后按逗号拆分否则直接使用环境变量中给定的集合列表。MONGO_UPDATE_COLLECTIONStrue时脚本会把导出的 validation schema 通过collMod命令回写为集合的 validator并设置validationAction: warn——即仅对不符合 schema 的写入发出警告而不拒绝属于温和的渐进式约束。深度定制采样方式改造 analyze.sh 中的 mongosh 查询如果你需要改变采样哪些文档RFC 指出可以编辑 schema_sampler/analyze.sh 文件。第 29 行是数据采样的核心命令mongosh ${MONGO_DATABASE} --quiet --eval var collection ${collection//\/}, outputFormatjson --username ${MONGO_USERNAME} --password ${MONGO_PASSWORD} --authenticationDatabaseadmin /schema_sampler/variety.js /schema_exports/analysis/${collection//\/}.json这条命令通过--eval向 Variety 注入collection与outputFormatjson两个全局变量将 variety.js 作为 mongosh 脚本执行并把 JSON 形式的分析结果写入/schema_exports/analysis/collection.json。定制采样方式的方法是修改--eval中的参数RFC 给出的两个例子添加find()例如var query { version: 2 }只对使用某个 schema 版本的记录采样添加limit()例如只返回前 5000 条记录。这两个参数对应 Variety 内置的配置项。在 variety.js 的readConfig中可以看到 Variety 支持的完整配置清单除collection、query、limit外还包括maxDepth默认 99嵌套对象的递归分析深度上限sort默认{_id: -1}采样前的排序方式影响limit截取的样本outputFormat默认asciiPoC 中设为json结果输出格式persistResults/resultsDatabase/resultsCollection是否将结果持久化到 MongoDB 及目标库表arrayEscape默认XX数组元素在 key 中的转义标记如genres.XX0XXexcludeSubkeys需要排除分析的子 key 列表lastValue是否记录每个 key 的最后观测值。这些参数为按查询过滤、按数量截断、按深度限制等采样策略提供了底层支撑也正是 RFC 开放问题中选择器的一种具体化实现。原理纵深从 Variety 分析结果到 $jsonSchemaVariety 的分析过程Varietyschema_sampler/variety.js的核心逻辑分四步序列化serializeDoc将每个文档递归展平为parentKey.key形式的一维 key 映射数组元素以arrayEscape 索引 arrayEscape默认XX0XX的形式命名如cast.XX0XX同时受maxDepth限制递归深度类型判定varietyTypeOf对每个值判定类型输出包括String、Number、NumberLong、Boolean、Date、ObjectId、BinData-subtype、Array、Object、null等合并统计mergeDocument跨文档累积每个 key 出现的类型计数types与出现总次数totalOccurrences结果转换convertResults生成形如{ _id: { key }, value: { types }, totalOccurrences, percentContaining }的条目数组其中percentContaining表示该字段在多少百分比的文档中出现——这正是 RFC 开放问题中字段出现频率阈值的原始数据来源。validation_exporter.js 的转换逻辑validation_exporter.js 读取/schema_exports/analysis/collection.json将其转换为 MongoDB$jsonSchema格式的 validation schema转换规则值得逐条解读按.拆分 Variety 的扁平 key还原嵌套结构逐层构建properties树类型冲突处理若某字段检测到多种类型typeKeys.length 1一律保守地降级为string代码第 19-23 行特殊类型映射objectid转为objectIdBSON 类型object类型会继续作为嵌套层展开其子属性结果写入/schema_exports/validation_schema/collection.json顶层包裹为{ $jsonSchema: { bsonType: object, required: [], properties: {...} } }。一个值得注意的细节转换器默认将出现多类型的字段归为string这是一种保守的最小公分母策略——宁可放宽类型也不让 schema 过早拒绝数据。这恰好对应 RFC 开放问题 2 中冲突类型如何取舍的讨论PoC 选择了最简单直接的默认策略而是否可配置则留待后续迭代。从 validation schema 到 Hasura GraphQL schemaRFC 明确指出回写后的 MongoDB validation schema 可以成为 Hasura 生成 GraphQL schema 的依据生成的 schema 先写回 MongoDBcollMod validator再由 Hasura 基于该数据源生成 GraphQL schema同时 RFC 标注了后续方向——利用 Hasura 的 logical models 直接生成 Hasura 表示的 schema从而让整个采样 → 分析 → 生成流水线与 Hasura 的类型系统无缝衔接。验证与调试查看容器日志运行docker logs mongodb_sampling可以看到采样容器内的执行过程——analyze.sh中大量使用 emoji 标注步骤如安装依赖、️枚举集合、分析、转换、回写方便快速定位流水线卡在哪一步检查中间产物./schema_exports卷包含两个子目录schema_exports/analysis/Variety 的原始分析结果每个集合一个 JSONschema_exports/validation_schema/转换后的$jsonSchema验证 schema每个集合一个 JSON。你可以直接查看这些 JSON 文件验证采样 → 分析 → 导出每个环节的输出是否符合预期。局限与未来方向从源码结构看该 PoC 有几个明显的边界读者在参考时应留意类型冲突策略硬编码多类型字段统一降级为string的逻辑写死在 validation_exporter.js 中尚不支持配置化依赖外部工具Variety 是 MIT 许可的第三方分析器schema_sampler/variety.js 文件头注释注明版权与许可证mongosh 则在 analyze.sh 中通过 apt 动态安装尚未进入 Hasura 核心RFC 开放问题 4 中核心工具 vs 外部工具集的归属问题尚未定论当前 PoC 以独立 docker-compose 形式存在并未合入 graphql-engine 主服务。RFC 中展望的未来方向包括将同一采样方法复用于其他 NoSQL 数据库厂商、通过 logical models 直接生成 Hasura schema 表示以及在类型冲突、字段频率阈值等方面引入可配置策略。如果你正在为 NoSQL 数据源设计自动 schema 推导工具这个 PoC 的采样 → 分析 → 生成 → 回写流水线是一份可以直接借鉴的完整参考实现。【免费下载链接】graphql-engineBlazing fast, instant realtime GraphQL APIs on all your data with fine grained access control, also trigger webhooks on database events.项目地址: https://gitcode.com/gh_mirrors/gr/graphql-engine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考