用連結、彙總與查找串起兩張表
情境:專案表要指向客戶表,並在不複製資料的情況下顯示客戶名稱與預算。
前置條件
你需要相關資料表的建表權限,以及來源表的 moderator、兩張表的資料列讀寫權限。本例把兩張表都放在聊天室 11111111-1111-4111-8111-111111111111。一般情況下,link 可以留在來源表的相同 scope,也可以在同公司內往上連:chatroom → 自己的 department/company,department → 自己的 company;向下、同層 sibling、無關 department 與跨公司目標都會被拒絕。以下 private 請求使用使用者 access token。
步驟
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 的 lookup | 可 | 可 |
| 已 picked 的 cardinality-many lookup | 可 | 可 |
formula——四則運算、比較、UPPER、LOWER、LEN | 可 | 可 |
含 IF、AND、OR 的 formula | 不可 | 不可 |
| link 欄位本身 | 只能判斷有無(is_empty / is_not_empty) | 永遠不可 |
含 IF/AND/OR 的 formula 在兩條路徑上都會被拒絕:IF/AND/OR formulas cannot be sorted/filtered yet; sort/filter is available on plain arithmetic/comparison/UPPER/LOWER/LEN formulas。以比較為根的 formula 輸出是布林值,因此只吃 eq、neq、is_null、is_not_null,而且值必須是真正的 true/false。
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。expand_links=true 時,expanded 只含目前使用者也有權讀取的目標資料;反向連結同樣不會繞過來源表 ACL。
常見錯誤
請直接查看欄位建立錯誤表、資料列建立錯誤表與hydrated read 錯誤表。
試試看
流程精靈可執行兩表、link、rollup 與 hydrated read 的基本流程;再用 API Playground 補上本例的 lookup 欄位。