據(jù)格式(NDF)完全指南:服務間數(shù)據(jù)導入導出的中間 JSON 格式)
后端數(shù)據(jù)庫GraphQL【免費下載鏈接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]項目地址https://gitcode.com/gh_mirrors/pr/prisma1點擊查看免費下載本篇技術(shù)指南圍繞 Prisma 服務中數(shù)據(jù)導入導出的核心中間格式——歸一化數(shù)據(jù)格式Normalized Data FormatNDF展開系統(tǒng)講解其 JSON 結(jié)構(gòu)、三種 value typenodes/lists/relations的字段約定與完整示例并結(jié)合當前倉庫中prisma import/prisma export命令的源碼實現(xiàn)深入剖析 NDF 在導入校驗、導出分頁與壓縮打包等環(huán)節(jié)中的實際運作方式。讀完本文你將能夠手寫合法的 NDF 數(shù)據(jù)文件理解 Prisma CLI 導入導出的底層調(diào)用鏈并能夠依據(jù)校驗規(guī)則定位并修復數(shù)據(jù)格式錯誤。NDF 是什么導入導出之間的中間格式The Normalized Data Format (NDF) is used as anintermediatedata format for import and export in Prisma services. NDF 為 JSON 定義了一種特定的結(jié)構(gòu)規(guī)范它既不直接對應數(shù)據(jù)庫的行也不直接對應 GraphQL 查詢結(jié)果而是把服務中的數(shù)據(jù)拆解為三類互補的值類型value type從而讓數(shù)據(jù)可以在不同 Prisma 服務、不同環(huán)境本地 / 云端 / 自建集群之間無損遷移。在 Prisma 的數(shù)據(jù)遷移實踐中prisma export產(chǎn)出的.zip內(nèi)部正是 NDF 文件按nodes/、lists/、relations/三個目錄組織而prisma import消費的也正是這種格式。相關(guān)的完整命令參考見 01-Data-Import.md 與 02-Data-Export.md。NDF 的三種值類型當使用 NDF 時數(shù)據(jù)被拆分到三種不同的值類型中Nodes節(jié)點包含節(jié)點的標量字段scalar fields數(shù)據(jù)Lists列表包含節(jié)點的列表字段list fields數(shù)據(jù)Relations關(guān)系包含通過關(guān)系字段relation fields連接兩個節(jié)點的數(shù)據(jù)。這種拆分是 NDF 的核心設計把一個對象拆成它的標量部分 它的列表部分 它與其他對象的關(guān)系三者分別獨立成文檔最終由id字段與_typeName字段互相錨定、重新組裝。頂層結(jié)構(gòu)valueType valuesNDF 文檔是一個 JSON 對象只包含兩個頂層鍵valueType表示文檔中數(shù)據(jù)的值類型取值只能是nodes、lists或relationsvalues實際數(shù)據(jù)是一個數(shù)組其元素結(jié)構(gòu)必須符合對應的值類型約定。該結(jié)構(gòu)在倉庫源碼中有精確的類型定義types.tsexport type ValueType nodes | relations | lists export type ScalarType number | string | boolean | null export interface Node { _typeName: string id: string [fieldName: string]: ScalarType | ScalarType[] } export interface RelationNode { _typeName: string id: string fieldName: string } export type RelationTuple [RelationNode, RelationNode] export interface ImportData { valueType: ValueType values: Node[] | RelationTuple[] }下面所有示例均基于如下數(shù)據(jù)模型與 Normalized-Data-Format.md 中的示例一致type User { id: String! unique firstName: String! lastName: String! hobbies: [String!]! partner: User }valueType 為 nodes 時的結(jié)構(gòu)當valueType為nodes時values數(shù)組內(nèi)每個對象的結(jié)構(gòu)如下{ valueType: nodes, values: [ { _typeName: STRING, id: STRING, scalarField1: ANY, scalarField2: ANY, ..., scalarFieldN: ANY }, ... ] }其中_typeName與id均為字符串_typeName指數(shù)據(jù)模型中 SDL 類型的名稱scalarFieldX占位符是該 SDL 類型上各標量字段的名稱。例如下面的 JSON 文檔可用于導入兩個User節(jié)點的標量值{ valueType: nodes, values: [ {_typeName: User, id: johndoe, firstName: John, lastName: Doe}, {_typeName: User, id: sarahdoe, firstName: Sarah, lastName: Doe} ] }從源碼校驗邏輯Validator.ts可以進一步確認nodes的約束_typeName必須存在且必須是數(shù)據(jù)模型由 SDL 解析出的類型集合中真實存在的類型id必須存在且為字符串數(shù)據(jù)模型中標為必填NonNull的標量字段必須全部出現(xiàn)在對象中否則拋出 lacks the following properties 錯誤出現(xiàn)數(shù)據(jù)模型中不存在的字段會被判為未知字段而報錯createdAt、updatedAt、id除外字段值必須匹配其聲明的標量類型見下文類型校驗器小節(jié)。valueType 為 lists 時的結(jié)構(gòu)當valueType為lists時values數(shù)組內(nèi)每個對象的結(jié)構(gòu)如下{ valueType: lists, values: [ { _typeName: STRING, id: STRING, scalarListField: [ANY] }, ... ] }_typeName與id同樣為字符串scalarListField占位符是該 SDL 類型上列表字段的名稱。需要注意與標量字段不同每個對象只能為一個列表字段提供值——即一個lists文檔中的對象只能攜帶一個列表鍵。例如下面的 JSON 文檔可用于導入兩個User節(jié)點的hobbies列表字段值{ valueType: lists, values: [ {_typeName: User, id: johndoe, hobbies: [Fishing, Cooking]}, {_typeName: User, id: sarahdoe, hobbies: [Biking, Coding]} ] }源碼中對應的校驗Validator.ts 與 Validator.ts保證了這種單向約定在nodes文檔中提供列表值會報錯List value ... mustnt be provided in a nodes definition在lists文檔中提供標量值也會報錯lists文檔中的值必須是數(shù)組數(shù)組內(nèi)每個元素再按元素標量類型逐一校驗。valueType 為 relations 時的結(jié)構(gòu)當valueType為relations時values數(shù)組內(nèi)每個元素的結(jié)構(gòu)如下{ valueType: relations, values: [ [ { _typeName: STRING, id: STRING, fieldName: STRING }, { _typeName: STRING, id: STRING, fieldName: STRING } ], ... ] }_typeName、id、fieldName均為字符串。_typeName指向數(shù)據(jù)模型中的一個 SDL 類型fieldName是該類型上的關(guān)系字段名。由于關(guān)系數(shù)據(jù)的目的是通過一條關(guān)系連接兩個節(jié)點values中每個元素本身是一對pair——寫作一個恰好包含兩個元素的數(shù)組這與nodes、lists中單個對象的形式不同。例如下面的 JSON 文檔通過partner關(guān)系字段在兩個User節(jié)點之間建立一條關(guān)系{ valueType: relations, values: [ [ { _typeName: User, id: johndoe, fieldName: partner }, { _typeName: User, id: sarahdoe, fieldName: partner } ] ] }源碼中的關(guān)系元組校驗Validator.ts非常嚴格每個 tuple 必須是數(shù)組且長度必須恰好為 2Relation tuple must have 2 nodestuple 內(nèi)兩個節(jié)點都必須滿足_typeNameid約束至少其中一個節(jié)點必須帶fieldName且該fieldName必須真實存在于對應類型的字段定義中否則報 points to a non-existing fieldName 錯誤。導入導出流程中的 NDF源碼視角NDF 不只是規(guī)范文檔它貫穿了 Prisma CLI 導入導出的完整執(zhí)行鏈路。本倉庫中相關(guān)實現(xiàn)位于 cli/packages/prisma-cli-core/src/commands/import 與 cli/packages/prisma-cli-core/src/commands/export 目錄下。導出分頁拉取并按 valueType 落盤prisma export的核心是 Exporter.ts。其關(guān)鍵流程download 方法為在工作目錄下創(chuàng)建.export/臨時目錄并預建nodes/、lists/、relations/三個子目錄makeDirs依次以nodes→lists→relations的順序調(diào)用導出服務接口每次請求攜帶{ fileType, cursor }其中cursor是{ table, row, field, array }四元組用于分頁游標ExportCursor每次返回的數(shù)據(jù)被包裝成標準 NDF 文檔寫入編號文件JSON.stringify({ valueType: fileType, values: data.out.jsonElements })文件名按六位前導零編號000001.json、000002.json……寫入對應類型目錄downloadFiles當游標之和小于 0 時停止拉取隨后將.export/目錄壓縮為最終交付的.zip文件zipIt并清理臨時目錄。因此一份prisma export產(chǎn)物的內(nèi)部結(jié)構(gòu)天然就是 NDF 的組織形態(tài)export.zip ├── nodes/000001.json # valueType: nodes ├── lists/000001.json # valueType: lists └── relations/000001.json # valueType: relations導入解壓、逐類型校驗與按序上傳prisma import的核心是 Importer.ts。其執(zhí)行流程upload 方法為若傳入的是.zip路徑則先解壓到.import/目錄unzip若傳入的是目錄則直接使用用 glob 收集nodes/、lists/、relations/三個目錄下的全部.json文件getFiles本地校驗對每個文件逐一JSON.parse后交給Validator校驗validateFiles。如果三個目錄一個文件都沒有直接報錯提示目錄結(jié)構(gòu)不合法錯誤信息中同樣指向 NDF 文檔按序上傳嚴格按nodes→lists→relations的順序逐文件上傳到服務端。這個順序是硬性要求——必須先有節(jié)點數(shù)據(jù)才能掛接列表字段與關(guān)系斷點續(xù)傳上傳進度通過state.json記錄{ nodes, lists, relations }三個數(shù)字文件名中的數(shù)字編號如000001.json→ 1用于比對已導入過的文件會跳過Skipping file ... (already imported)從而支持中斷后繼續(xù)導入saveState / getState / getNumber。導入前的 NDF 校驗器Validator.ts 是 NDF 數(shù)據(jù)質(zhì)量的守門員。它以數(shù)據(jù)模型的 SDL 字符串為輸入用 GraphQL 解析器將其轉(zhuǎn)為 AST再據(jù)此構(gòu)建每個類型的字段映射、必填字段清單、枚舉取值表astToTypes / astToEnums隨后對三種 value type 分別執(zhí)行校驗。其中內(nèi)置的標量類型校驗器validators值得注意SDL 類型校驗規(guī)則源碼實現(xiàn)ID/String必須是字符串isStringInt可解析為數(shù)字且(x | 0) x即為整數(shù)Float必須是數(shù)字isNumberDateTime必須是字符串且匹配 ISO-8601 風格正則\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d([-][0-2]\d:[0-5]\d\|Z)Boolean必須是布爾值isBooleanJson必須是對象typeof value object自定義枚舉值必須包含在 SDL 枚舉定義中makeEnumValidators這些規(guī)則在測試中有充分的覆蓋例如 Validator.test.ts 驗證了缺失_typeName、未知_typeName都會拋錯Validator.test.ts 驗證了id為數(shù)字 25 時拋錯、為字符串25時通過。倉庫內(nèi)置的真實 NDF 示例倉庫的導入測試 fixturecli/packages/prisma-cli-core/src/commands/import/fixtures/basic提供了一套可直接對照學習的完整 NDF 數(shù)據(jù)數(shù)據(jù)模型 types.graphqlPost含title、description、tags: [String!]!、state: PostState!枚舉、comments關(guān)系與Comment含text、post關(guān)系節(jié)點數(shù)據(jù) nodes/000001.jsonvalueType: nodesPost攜帶標量字段與枚舉字段stateComment只攜帶text列表數(shù)據(jù) lists/000001.jsonvalueType: lists每個Post對象僅攜帶一個列表鍵tags關(guān)系數(shù)據(jù) relations/000001.jsonvalueType: relations每個 tuple 由Post.comments與Comment.post這一對關(guān)系字段構(gòu)成進度狀態(tài) state.json初始狀態(tài)為三個計數(shù)器均為 0。生成該 fixture 的腳本見 makeData.ts其數(shù)據(jù)生成邏輯與 NDF 的標量 / 列表 / 關(guān)系三分離模型一一對應適合作為手寫 NDF 數(shù)據(jù)的參考模板。手寫 NDF 的實踐要點綜合規(guī)范文檔與源碼實現(xiàn)在手動構(gòu)造 NDF 文件時應當遵循以下要點頂層結(jié)構(gòu)固定每個 JSON 文件都必須且只能包含valueType與values兩個鍵valueType只能取nodes、lists、relations三者之一三件套齊備一次完整的導入需要同時提供nodes/、lists/、relations/三個目錄內(nèi)容可以為空文件集但目錄結(jié)構(gòu)必須存在否則 CLI 會報目錄結(jié)構(gòu)錯誤id是錨點三種 value type 都通過_typeNameid定位到具體節(jié)點id必須為字符串且與數(shù)據(jù)庫中該節(jié)點的唯一標識一致類型正確性標量字段值必須與 SDL 聲明的類型匹配如DateTime需符合 ISO-8601 格式、枚舉值必須合法否則會在本地校驗階段即被攔截列表與標量互斥列表字段只能出現(xiàn)在lists文檔中且每個對象只放一個列表字段標量字段只能出現(xiàn)在nodes文檔中關(guān)系成對出現(xiàn)relations的values中每個元素必須是恰好兩個節(jié)點的數(shù)組兩個節(jié)點分別從關(guān)系兩端如Post.comments與Comment.post描述同一條關(guān)系上傳順序不可變即便自行編寫導入腳本也應遵循服務端 nodes → lists → relations 的依賴順序先有節(jié)點再掛列表和關(guān)系。小結(jié)歸一化數(shù)據(jù)格式NDF是 Prisma 數(shù)據(jù)導入導出體系的基石它以nodes/lists/relations三種值類型把數(shù)據(jù)庫內(nèi)容正交切分用統(tǒng)一的_typeNameid作為跨文檔的關(guān)聯(lián)錨點配合 CLI 的本地校驗、按序上傳與斷點續(xù)傳機制實現(xiàn)了數(shù)據(jù)在不同 Prisma 服務之間的可靠遷移。無論是閱讀prisma export產(chǎn)物、手工構(gòu)造prisma import輸入還是排查導入報錯理解本文所講的 NDF 結(jié)構(gòu)、字段約束與校驗規(guī)則都能直接派上用場。進一步的實踐入口完整的導入導出命令用法見 01-Data-Import.md 與 02-Data-Export.mdCLI 命令參考見 prisma-import.md數(shù)據(jù)遷移的端到端工作流可參考 01-Data-Export--Import.md。贊分享后端數(shù)據(jù)庫GraphQL【免費下載鏈接】prisma1 Database Tools incl. ORM, Migrations and Admin UI (Postgres, MySQL MongoDB) [deprecated]項目地址https://gitcode.com/gh_mirrors/pr/prisma1點擊查看免費下載相關(guān)推薦Prisma Normalized Data Format (NDF) 完全指南結(jié)構(gòu)化 JSON 實現(xiàn)數(shù)據(jù)導入導出的中間格式Prisma Normalized Data Format NDF 完全指南結(jié)構(gòu)化 JSON 實現(xiàn)數(shù)據(jù)導入導出的中間格式 Normalized Data Fo后端數(shù)據(jù)庫GraphQLPrisma 數(shù)據(jù)導入導出核心Normalized Data Format (NDF) 中間格式完全解析Prisma 數(shù)據(jù)導入導出核心Normalized Data Format NDF 中間格式完全解析 Normalized Data FormatNDF是后端數(shù)據(jù)庫GraphQLPrisma 數(shù)據(jù)導出與導入實戰(zhàn)使用 NDF 格式在服務與 stage 之間遷移數(shù)據(jù)Prisma 數(shù)據(jù)導出與導入實戰(zhàn)使用 NDF 格式在服務與 stage 之間遷移數(shù)據(jù) 本教程基于 Prisma 開源倉庫 prisma1 講解數(shù)據(jù)導出與導后端數(shù)據(jù)庫GraphQL上一篇Mac Mouse Fix終極指南3步將普通鼠標升級為macOS生產(chǎn)力神器下一篇Slang 編譯目標Targets、能力Capabilities與配置文件Profiles完整指南創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考