用連結、彙總與查找串起兩張表
情境:專案表要指向客戶表,並在不複製資料的情況下顯示客戶名稱與預算。
前置條件
你需要相關資料表的建表權限,以及來源表的 moderator、兩張表的資料列讀寫權限。本例把兩張表都放在聊天室 11111111-1111-4111-8111-111111111111。一般情況下,link 可以留在來源表的相同 scope,也可以在同公司內往上連:chatroom → 自己的 department/company,department → 自己的 company;向下、同層 sibling、無關 department 與跨公司目標都會被拒絕。以下 private 請求使用使用者 access token。
Chatroom table 的向上 link,現在會讓 rollup、lookup 與符合條件的 lookup fallback 依聊天室的有效公司解析,回傳可讀目標值。不存在、不可讀或跨公司的目標仍不會提供值。Link preview 也依同一有效公司驗證;計算欄 preview 若遇到精確 decimal 無效運算或溢位,會回 400 並帶字串 detail。
步驟
1. 建立目標表與來源表
先透過 tables.create 建立「客戶」,再建立「專案」。記下兩個回應中的 id,以及客戶表 settings.column_mapping 裡「名稱」與「預算」的內部 ID。
POST /private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/tables
Content-Type: application/json
{
"name": "客戶",
"description": "專案客戶主檔",
"schema_definition": {
"columns": [
{ "name": "名稱", "type": "string", "required": true },
{ "name": "預算", "type": "float" }
]
}
}POST /private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/tables
Content-Type: application/json
{
"name": "專案",
"description": "進行中的客戶專案",
"schema_definition": {
"columns": [
{ "name": "專案名稱", "type": "string", "required": true }
]
}
}以下假設客戶表是 22222222-2222-4222-8222-222222222222、專案表是 33333333-3333-4333-8333-333333333333。
2. 在專案表建立 link 欄位
columns.create 在這一步定義關係:target_table_id 指向客戶表;cardinality: "one" 表示一個專案只選一位客戶。保留回應中的 link 欄位 column.id。
POST /private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/tables/33333333-3333-4333-8333-333333333333/columns
Content-Type: application/json
{
"name": "客戶",
"type": "link",
"target_table_id": "22222222-2222-4222-8222-222222222222",
"cardinality": "one"
}以下使用 link 欄位 ID col_44444444_4444_4444_8444_444444444444。
3. 建立 rollup 與 lookup
依 columns.create 的欄位契約,link_field 與 target_column 都使用內部 ID:前者固定關係,後者即使顯示名稱改名仍可正確計算。rollup 對預算做 sum;lookup 原樣帶回客戶名稱。兩者都是唯讀計算欄位。
POST /private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/tables/33333333-3333-4333-8333-333333333333/columns
Content-Type: application/json
{
"name": "客戶預算",
"type": "rollup",
"link_field": "col_44444444_4444_4444_8444_444444444444",
"target_column": "col_55555555_5555_4555_8555_555555555555",
"aggregation": "sum"
}POST /private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/tables/33333333-3333-4333-8333-333333333333/columns
Content-Type: application/json
{
"name": "客戶名稱",
"type": "lookup",
"link_field": "col_44444444_4444_4444_8444_444444444444",
"target_column": "col_66666666_6666_4666_8666_666666666666"
}不要在資料列建立或更新請求中傳入 rollup/lookup 值;伺服器會從 link 關係計算它們。
4. 建立目標資料列,再寫入 link
使用 records.create 先建立客戶並保留資料列 id,再建立專案。資料列建立可用顯示名稱當 key;link 值即使 cardinality 是 one,仍以目標 record ID 陣列傳入。
POST /private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/tables/22222222-2222-4222-8222-222222222222/records
Content-Type: application/json
{
"data": {
"名稱": "北辰商事",
"預算": 1250000
},
"created_by_ai": false
}POST /private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/tables/33333333-3333-4333-8333-333333333333/records
Content-Type: application/json
{
"data": {
"專案名稱": "網站重構",
"客戶": ["77777777-7777-4777-8777-777777777777"]
},
"created_by_ai": false
}以下假設專案 record ID 是 88888888-8888-4888-8888-888888888888。
5. 讀取 hydrated 關係
records.hydrated 會一次回傳目前 record、可讀的反向關係、表格資訊,並可展開 link 目標。
GET /private/module/custom_tables/chatroom/11111111-1111-4111-8111-111111111111/tables/33333333-3333-4333-8333-333333333333/records/88888888-8888-4888-8888-888888888888/hydrated?expand_links=true&limit_per_table=20已登入的產品也可從絕對路徑 GET /private/module/custom_tables/linked-records/guide 取得嵌入式 Markdown 說明,目錄項目是 guide.linkedRecordsGuide。本頁將該說明的核心關係模型改寫為可執行流程,並以目前 catalog 修正過時限制。
與舊版連結說明不同,現在計算欄位是可以篩選與排序的——REST 這一側走 records.search 或已儲存檢視,而從這個版本起,agent 那一側也可以了。下一節就是精確的適用範圍;不要把舊版「一律不可篩選」當成現況。
對剛建好的計算欄位篩選與排序
AI 現在可以在伺服器端回答「預算彙總超過 10000 的客戶」與「客戶預算最大的十個專案」。以前它是把整張表一頁一頁抓下來、在腦袋裡比對 rollup 格子——只要超過第一頁就是錯的——而且隨附的 cheat sheet 明白告訴它計算欄位在查詢上是唯讀的。兩側都編譯成同一組關聯子查詢下推,所以 ACL 底線與 null 語意完全一致。
真正符合資格的範圍比「計算欄位」窄:
| 欄位 | 篩選 | 排序 |
|---|---|---|
rollup、cardinality 為 one 且沒有 fallback 的 lookup | 可 | 可 |
已 picked 且沒有 fallback 的 cardinality-many lookup | 可 | 可 |
formula——四則運算、比較、UPPER、LOWER、LEN、精確小數函式 | 可 | 可 |
含 IF、AND、OR、CONCAT、日期函式、[Link -> Column] 引用,或以 fallback lookup 為輸入的 formula | 不可 | 不可 |
| link 欄位本身 | 可判斷成員(eq / in 目標紀錄 ID)與有無(is_empty / is_not_empty) | 永遠不可 |
含 IF、AND、OR、CONCAT、TODAY、DATEDIFF、YEAR 或 MONTH 的 formula 在兩條路徑上都會被拒絕:IF/AND/OR formulas cannot be sorted/filtered yet; sort/filter is available on plain arithmetic/comparison/UPPER/LOWER/LEN formulas。[Link -> Column] 引用會被拒絕,訊息為 cross-table refs cannot be sorted/filtered; declare a cardinality-one numeric LOOKUP column and sort/filter that;帶有 fallback 的 lookup,或讀取它的 formula,則只能在求值時計算(eval-only)。以比較為根的 formula 輸出是布林值,因此只吃 eq、neq、is_null、is_not_null,而且值必須是真正的 true/false。decimal 的 rollup、lookup 或 formula 要用像 "10000.00" 的小數字串比較;若範圍內有列無法精確求值,請求會以 ct.numeric_overflow 或 ct.numeric_invalid 失敗。使用乘法、DECIMAL、QUANTIZE 或 DIVIDE 的 decimal formula,在篩選與排序時會編譯成精確的 SQL;無法精確編譯時,REST 回 400 computed decimal expression is not exactly SQL-representable: <reason>(篩選比較則是對應的 computed decimal comparison is not exactly SQL-representable: <reason>)。
link 欄位仍然永遠不能排序。在 agent 這一側,拒絕訊息現在是 link 專用的——Column '<c>' is a link column and cannot be sorted on — use custom_tables_traverse_links for link analysis.——而 cardinality 為 one 的 link 在那裡可以當聚合的 group_by 鍵,只是分組鍵是目標 record id 而不是名稱,而且 NULL 那一組刻意把三種情況混在一起:這一列沒有連結、目標被軟刪除、或呼叫者的 scope 看不到目標。
兩側共用同一道硬上限:50,000 筆存活資料列。超過就直接拒絕,不會退化、不會分頁、也沒有備援:
computed filters are refused on tables with more than 50000 live records (this table has <N>) — narrow the data with regular filters first
sorting by computed columns is refused on tables with more than 50000 live records (this table has <N>) — narrow the data with regular filters first這句補救建議要抱著懷疑讀。那個筆數是在任何條件編譯之前就檢查的,所以再加一般 filters 也解不開這道閘;只有換一張比較小的表才行。
另一個陷阱是 null,而且它正是這一頁該提 ACL 的理由。計算欄位的格子在「link 解不到東西」與「呼叫者讀不到那張受管的目標表」兩種情況下都是 null,而 null 格子只會被 is_null 命中,其他運算子一律不中。所以「沒有客戶預算的專案」會默默把「客戶是呼叫者看不到的那些」專案也算進去。任一側單次請求最多 AND 三個計算欄位條件。REST 的參數形狀見查詢模型,工具參數與錯誤字串見 Agent 工具箱。
你會看到什麼
專案資料列的 link 指向「北辰商事」,lookup 顯示客戶名稱,rollup 顯示 1250000.0(float 的加總)。expand_links=true 時,expanded 會把每個 link 欄的顯示名稱對應到 { total, records }:total 是 live 連結目標的實際數量,records 依連結順序最多列出 50 筆;呼叫者無權讀取的目標——以及呼叫者對目標表的讀取層級為 filtered 時的所有目標——只會是只有 ID 的 stub,帶 readable: false 且 data 為空。反向連結不會繞過來源表 ACL:來自呼叫者無權讀取、或其 link 欄位在來源表上對呼叫者被隱藏之來源表的群組會被省略,被隱藏的 link 欄位也不會出現在 expanded。
常見錯誤
請直接查看欄位建立錯誤表、資料列建立錯誤表與hydrated read 錯誤表。
試試看
流程精靈可執行兩表、link、rollup 與 hydrated read 的基本流程;再用 API Playground 補上本例的 lookup 欄位。