Skip to Content
操作指南檔案匯入

從檔案擷取並匯入資料

情境:你收到一個訂單檔案,想先檢查伺服器推測的欄位,再決定建立新表或寫入既有表。

前置條件

你需要目標 scope 的存取權。Chatroom extraction 使用 room access gate;department extraction 與 preview 只要求部門屬於呼叫者的公司,不要求部門管理權限;company extraction 需要 company-management access,各 scope 的拒絕條件不同;跨公司部門回 404。若選擇既有表,還需要該表的 insert 權限。本例使用聊天室 11111111-1111-4111-8111-111111111111。匯入大小由部署環境的 CUSTOM_TABLE_IMPORT_MAX_BYTES 控制,預設為 50 MiB;所有 private 請求使用使用者 access token。

Chatroom/company 的 403 detail 文字仍依 scope 而定。

部門上傳與寫入權限(v5.10.0)

部門所屬公司的已登入使用者可擷取與預覽 department 匯入 session,不再要求部門管理權限。上傳或預覽不會授予資料表存取權。具有既有表 insert 權限時選擇「匯入既有表」;要「建立新表」仍須部門管理權限。權限撤銷後,後續 map 請求會被拒絕;insert 權限也不代表匯入列的 can_edit 為 true。Session 必須符合請求的部門;不存在、過期或錯誤 scope 都回 404。

後端 #1261  已以真實 staging E2E 驗證兩列 XLSX、僅新增權限的讀回、拒絕建新表與撤權行為;修正已隨 v5.10.0 發佈。

步驟

1. 上傳檔案並啟動 extract

將 multipart 欄位 file 送給 import.extract;回應會立刻給 ticket_id,不代表擷取已完成。

curl -X POST \ -H "Authorization: Bearer <user-access-token>" \ -F "file=@orders.csv;type=text/csv" \ "https://api.example.invalid/private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/import/extract"

以下假設 ticket 是 44444444-4444-4444-8444-444444444444

2. 輪詢 extract ticket

import.extract 使用共用非同步 watchdog。輪詢下列精確路徑,直到 body.statuscompletedfailedprocessing 時依 body.current_step 顯示進度。

GET /public/task/44444444-4444-4444-8444-444444444444

成功時從 body.import_session_id 取出 session ID。若 watchdog 的 ttl-1,ticket 已不存在或過期;不要猜一個 session ID。

3. 檢查 session preview

import.sessionPreview 的 preview 可能包含多個候選表。對你要匯入的候選,保留原樣的 signature,並檢查 source_columnsproposed_schemasample_rowsrow_count

GET /private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/import/33333333-3333-4333-8333-333333333333

後續請求的 signature 必須來自這個 session;它用來鎖定候選資料,不是讓客戶端重新計算的欄位。

4. 寫入前檢查型別相容性

每個擷取出的儲存格送進 row mapper 時都是字串。Preview 的型別推測只是一項建議:它只會提出 stringtextintegerfloatdatedatetime,不會提出 boolean、任何 list 型別、principal、JSON 或 computed 型別。全空欄會推測為 string;只要任一非空值超過 256 個字元,字串欄就會推測為 text

調整推測 schema 或對應既有表時,請依下表判斷:

目標欄位型別檔案匯入行為
stringtext以字串接受,仍須通過目標欄位的一般長度與 required 檢查。
integerfloatRecord validator 會轉換數字字串;格式錯誤的數字會使該列無效。
boolean不相容於一般擷取出的儲存格。"true""1""yes" 等值仍是字串,record contract 要求 JSON boolean,因此會拒絕。
date只接受 record contract 的標準 YYYY-MM-DD 格式。
datetime只接受 record contract 的標準 YYYY-MM-DD HH:MM 格式。Preview sniffer 也會辨識 T 分隔符與選填的秒數,但寫入 validator 不接受;因此 preview 仍可能提出一個會讓資料列無效的型別。
select字串必須與某個已設定 option 完全相同才可寫入。
multi_select不相容於一般擷取出的儲存格:record contract 要求陣列,但 importer 只提供一個原始字串。
attachment不相容於一般擷取出的儲存格:record contract 要求 attachment ID 陣列,不接受檔名或分隔字串。
usersocial_client字串只有在它是該資料表 tenant 所擁有 principal 的原始 ID 時才可寫入;不會解析名稱或電子郵件地址。
principal字串只有在它是帶標籤的 cell(user:<id>smc:<id>room:<id>)、該 principal 屬於資料表 tenant,且 smc:room: 的聊天室仍存活時才可寫入。裸 ID 會以形狀錯誤被拒,名稱也不會被解析。
json在派送資料列前即被拒絕為匯入目標。
linkrolluplookupformula會被拒絕為 computed 匯入目標。Create-from-import 完成後再新增這些欄位。

Sniffer 只檢查 date 與 datetime 的字串形狀,不檢查日曆日期是否有效。請把 preview 視為建議,派送前先驗證代表性資料。

5. 在建立新表與寫入既有表之間二選一

若檔案代表新的資料集,走 import.createFromImportschema_definition.columns 必須與候選欄位保持相同數量與順序;可以改名、調整支援的型別與 required 設定,但不能在此新增或刪除位置,也不能建立 link、rollup、lookup 或 formula。這些衍生欄位請在匯入後另行建立。

呼叫 create 前,請先在 client 端核對欄位數量。後端目前會先建立並 commit 資料表,才比較候選欄數與 schema_definition.columns;數量不符時雖然回 400,新表仍會以空表留下。不要假設這個 400 沒有副作用。

POST /private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/import/33333333-3333-4333-8333-333333333333/create Content-Type: application/json { "signature": "a3f5f7d9b1c3e5f709182736455463728190aabbccddeeff0011223344556677", "table_name": "匯入訂單", "description": "來自七月 CSV 的訂單", "schema_definition": { "columns": [ { "name": "訂單編號", "type": "string", "required": true } ] }, "skip_invalid": true }

若資料應追加到現有表,使用 import.mapIntoTablecolumn_map 的 key 是 preview 的來源欄名,value 是既有表的顯示名稱或內部欄位 ID;只能對應可寫入、可見的 stored 欄位,且必須符合上方的相容性表。JSON 與 computed 目標會被拒絕。沒有列入 map 的來源欄不會寫入。

POST /private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/tables/22222222-2222-4222-8222-222222222222/import/33333333-3333-4333-8333-333333333333 Content-Type: application/json { "signature": "a3f5f7d9b1c3e5f709182736455463728190aabbccddeeff0011223344556677", "column_map": { "order_no": "訂單編號" }, "skip_invalid": true }

skip_invalid 只控制 row mapper 對「缺少 required 值」的檢查。設為 true 時,缺少 required mapped value 的資料列會在 bulk 派送前被省略;目前 import 回應與 ticket 都不會揭露這個 mapper skip 計數。設為 false 時,請求會在第一筆這類資料列停止,不會派送 insert。Create 分支此時可能已建立空表。

型別與 schema 驗證之後才在非同步 bulk worker 執行,不受 skip_invalid 影響。原始字串無法滿足目標型別時,會成為 ticket 的逐列錯誤;其他資料列可能已 commit,而 terminal status 是 completed_with_errors。寫入前請比較來源 row count 與派送/ticket totals、檢查 ticket errors,並審查 preview、型別相容性與 required 欄位。

6. 輪詢寫入 ticket

兩個分支都會回傳新的 ticket_id;create 分支還會立即回傳 table_id。對新的 ticket 使用同一個 watchdog:

GET /public/task/55555555-5555-4555-8555-555555555555

只有在 terminal status 為 completed 時才把流程標為成功。completed_with_errors 要檢查列級錯誤;held_for_approval 表示整批尚未寫入,應接到核准流程failed 則保留 ticket 回應供診斷。

你會看到什麼

extract ticket 完成後會提供 session ID;preview 會顯示候選 schema 與樣本。選擇 create 時會新增一張表,選擇 map 時會保留原表 schema;最終 ticket 會報告實際寫入結果,而不是只代表已排入佇列。

常見錯誤

請直接查看檔案擷取錯誤表preview 錯誤表建立新表錯誤表對應既有表錯誤表

試試看

檔案匯入流程精靈會保留 extract ticket、session ID 與 signature,並讓你在 create 和 map 分支之間選擇。

Last updated on