Skip to Content
核心概念欄位型別查找

查找型別:lookup

用途

lookup 透過本表自己的 link 欄,直接帶出目標列的一個純量欄位。例如訂單已用「客戶」link 指到客戶表,便可用 lookup 顯示該客戶的 Email。它不複製資料,也不執行自訂運算;目標值變更後,下一次讀取就會反映新值。

建立 schema

先建立 link 欄,再送出 columns.create body:

{ "name": "客戶 Email", "type": "lookup", "link_field": "客戶", "target_column": "Email", "description": "從客戶表即時帶出的聯絡信箱" }

link_field 必須是本表的 link,target_column 必須是該 link 目標表的儲存型純量欄。兩者都可用顯示名稱或內部鍵輸入,持久化時會改成 rename-stable 的內部鍵。

合法與不合法的值

lookup 是唯讀欄;合法的紀錄 payload 只寫 link,不寫 lookup:

{ "data": { "客戶": ["33333333-3333-4333-8333-333333333333"] } }

自行送出帶出的 Email 會被拒:

{ "data": { "客戶": ["33333333-3333-4333-8333-333333333333"], "客戶 Email": "buyer@example.com" } }

設定時把 target_column 指到 linkrolluplookupformulamulti_selectattachmentjson 也不合法;lookup 可帶出 stringtextintegerfloatbooleandatedatetimeselectusersocial_client 純量值。Principal lookup 回傳的是儲存的原始身分 ID,不是 principal 型別欄在所屬表讀取時產生的顯示物件。

顯示與回傳

回傳形狀由 link cardinality 決定。one link 回單一純量:

{ "data": { "客戶": ["33333333-3333-4333-8333-333333333333"], "客戶 Email": "buyer@example.com" } }

many link 回與 link ID 順序對應的值陣列;除非該 lookup 帶了 pick(見下節),此時 cell 是單一值。不可讀或不存在的單一目標位置會是 null。沒有 fallback 時,沒有連結、依賴失效或整張目標表不可讀都會讓 cell 成為 null。符合條件的純量 lookup 可以帶 fallback,此時真正未連結的 primary 可查 defaults;但權限拒絕刻意不會被當成 primary 空值。

pick 把 many lookup 收斂成純量

建立在 cardinality-many link 上的 lookup 可以額外帶一個 pick 物件。它會依某個可排序欄位對「被連到的目標列」排名並取第一名(argmax),讓 cell 呈現單一純量而不是陣列:

{ "name": "最新一張發票金額", "type": "lookup", "link_field": "發票", "target_column": "金額", "pick": { "order_column": "開立日期", "direction": "desc" } }

這個欄位現在顯示「最近開立的那張連結發票的金額」— 也就是「最新發票金額」/「最後看診日」這一類 primitive,過去只有 cardinality-one link 做得到。

欄位型別意義
order_columncolumn reflink 目標表上的可排序 stored 欄integerfloatdatedatetime)。可用顯示名稱或內部鍵輸入,持久化為目標表的內部鍵。
direction"asc" / "desc""desc" 取最大值(最新/最高),"asc" 取最小值(最早/最低)。必填,沒有預設值。

排名規則是明確的,而且 SQL pushdown 與 Python 讀取路徑完全一致 — 你在畫面上看到的值,就是 filter/sort 比對到的那個值:

  1. 只有 live 且呼叫者可讀的目標列參與排名。
  2. order_column 為 NULL 的列一律排在最後,與 direction 無關。
  3. 接著才套用指定的 direction。
  4. 平手時以 link 自己的 (position, id) 決勝。若 order 欄不可排序或已失效,會退回這個 (position, id) 後備方案,而不是報錯。

數值型 order 欄使用較寬的數值 cast 比較,因此 picked lookup 可以安全地對非常大或非常精密的數字排名 — 比多欄 sort key 使用的 cast 更寬。

pick 解鎖了什麼

因為 picked cell 是純量,三件過去 unpicked many lookup 做不到的事變成合法。前兩項還要求 lookup 沒有同時帶 fallback;fallback 是下方說明的 eval-only 例外。

  • 可以用 computed_filters 篩選。
  • 可以用 sort_by 排序(僅限單欄排序 — 計算欄永遠不是合法的多欄 sort key)。
  • 可以當成 formula 運算元,其型別就是目標欄自己的型別。要做算術,目標仍必須是數值型。

未帶 pick 的 many lookup 維持舊行為與舊錯誤:computed filter on '<col>': cardinality-"many" lookups render list cells and cannot be filtered or sorted (kept 400 by design)

欄位建立之後,pick 永遠不能新增、修改或移除。columns.update 根本沒有 pick 欄位,REST 會回 Only name/description can be updated on lookup columns;IaC plan 只要改動任一 pick 子欄位就是硬性 plan error:only name/description can be updated on lookup columns (got: pick); to change computed config delete and recreate the column (state: absent + new line)。要改 pick 就得刪除並重建該欄位,並重新處理所有引用它的設定。

pick 會在哪些情況被拒絕

  • 用在 cardinality-one lookup 上:pick is only valid on a cardinality-many lookup. a cardinality-one link already yields a scalar — drop pick
  • 用在 rollup 欄上:pick is a lookup-only field. argmax pick collapses a many-lookup; rollups aggregate instead
  • 用在 link、formula、純量、json、attachment 與 principal 欄上(由 per-type field matrix 擋下)。
  • order_column 不可排序:pick order_column '<name>' is type <type> — argmax ordering requires an orderable stored column (integer/float/date/datetime),後面會附上目標表可排序欄位的候選清單。用文字 狀態 或另一個計算欄來排名,都會在這裡失敗。
  • 多帶任何子 key:這個物件是 extra: "forbid",打錯字會 fail-closed 回 pick has unsupported field(s): [...]. pick takes exactly order_column + direction,而不是默默存下一個永遠不生效的設定。

在 IaC 中撰寫 pick

pick.order_column在 link 目標表上解析的 column ref,不是在近端表上;它屬於 cross-reference 欄位集合,因此 drift 是以翻譯後的值比較:

{"kind":"column","table":"orders","ref":"latest_invoice_amount","spec":{"name":"Latest invoice amount","type":"lookup","link_field":"invoices","target_column":"amount","pick":{"order_column":"issued_on","direction":"desc"}}}
  • 沒有寫 link_field 會在 import 階段 fail-closed:pick.order_column requires link_field (picked lookup) to resolve its owning table
  • ref 不存在時,plan 階段回報 unknown column ref '<target>.<col>' (pick.order_column)
  • Export 會 fail-closed 地把內部鍵反向翻譯回 ref,因此匯出的 bundle 可以來回轉換而不洩漏原始 col_<hex>。Export 也會依跨表相依順序輸出 table(link/lookup 的目標排在引用者之前),讓匯出的 bundle 能在 differ 的單趟、依文件順序的欄位驗證下順利重新 apply。

fallback 補上 null 純量 lookup

fallback 會在 primary lookup 之後增加一次 defaults-table probe。它適合「有客戶折扣時使用客戶折扣,否則使用區域預設值」這類契約:

{ "name": "有效折扣", "type": "lookup", "link_field": "客戶方案", "target_column": "折扣", "fallback": { "table_id": "44444444-4444-4444-8444-444444444444", "match": { "區域": "$row.區域", "種類": "標準" }, "target_column": "預設折扣" } }

Defaults table 是直接參照,不是另一段 link hop。它可以與本表同 scope,也可以位於同公司中合法的較廣 scope,因此 chatroom 表可繼承 department/company defaults,不必把預設值複製到每個房間。

欄位精確契約
table_idDefaults-table UUID。不存在、外公司與不可到達 scope 都使用相同的 non-oracular 錯誤。
match一至兩組等值配對。Key 是 defaults table 的 stored scalar;value 是相容的 scalar literal,或 $row.<本表 stored scalar>
target_columnDefaults table 上要帶出的 stored scalar 欄位。

只有 primary lookup 會呈現一個純量時才能使用 fallback:cardinality-one lookup,或已經用 pick 收斂的 cardinality-many lookup。一般 many lookup 會呈現清單,沒有單一 primary 值可供 fallback,因此會被拒絕。巢狀/串接 fallback 與未知子 key 也都會被拒。

執行與權限語意

Primary 值非 null 時一律優先。只有純量 primary 是真正的 null 時才執行 fallback,包括沒有 link、可讀目標 cell 的值為 null,或 picked winner 的帶出 cell 為 null。後端接著按 record ID 升冪,選出第一筆同時符合所有配對、live 且可讀的 defaults row。沒有命中,或 $row match 輸入為 null 時,lookup 維持 null。

權限拒絕永遠不會啟動 fallback。若 primary table、target row、target column、picked ordering key、defaults table、defaults row、defaults columns 或 $row 輸入對呼叫者不可見,cell 維持 primary-only/null 行為。Fallback 可以補「不存在的值」,但不能洗出呼叫者被拒絕的值。這裡保留一個刻意接受的 residual signal:能讀 defaults table 的呼叫者,可區分「primary 不存在而取得 default」與「primary 被拒絕而維持 null」。此外,唯一 target 若已 soft-delete,會依平台一貫的 deleted-as-absent 規則視為不存在/未連結,因此可能啟動 fallback。

Fallback probe 會依 defaults table 與 match tuple 去重,且所有 fallback 欄位共用一份 page-wide budget:min(5000, max(50, page row 數 × fallback 欄位數))。若病態的大 page 耗盡 budget,後端會記錄 warning;未執行的 probe 會呈現 null,因此可能低估設定的 default。

帶 fallback 的 lookup 在 v1 是 eval-only。即使 pick 原本會讓 lookup 可篩選與排序,它仍不能用於 computed_filters 或 computed sort_by。新增 fallback 時,若 saved view 依賴這類 pushdown 也會被拒。Fallback 設定與 link_fieldtarget_columnpick 一樣,建立後不可變更。

在 IaC 中撰寫 fallback

IaC 使用可攜的 table ref table,不是 REST 的 UUID 欄位 table_id。Match keys 與 target_column 是 defaults table 的 refs;$row value 則是 lookup 所屬表的 refs:

{"kind":"column","table":"orders","ref":"effective_discount","spec":{"name":"Effective discount","type":"lookup","link_field":"customer_plan","target_column":"discount","fallback":{"table":"discount_defaults","match":{"region":"$row.region","kind":"standard"},"target_column":"default_discount"}}}

Plan 會 fail closed 地解析所有 refs,並以正規化值比較 drift。Export 會做反向翻譯,因此輸出的是 fallback.table 與 authored column refs,不會帶出環境限定 ID 或原始 col_<hex> key。

Lookup 與 formula 的差別

問題lookupformula
資料從哪裡來沿本表 link 讀目標列對欄位引用執行運算
設定link_field + target_column(可選 pick 和/或 fallbackexpression
是否原樣帶出目標值否,回傳運算結果
many link回陣列;帶 pick 時回單一純量;fallback 要求純量形式跨表引用只接受 one link
可否寫入

需要「顯示客戶 Email」時用 lookup;需要「信用額度乘以風險係數」時用 formula,並引用數值 lookup 或使用公式的 one-link 跨表引用。

注意事項

  • lookup 不接受 aggregationfilterexpression。除了必填的 link_fieldtarget_column,cardinality-many link 上可帶 pick = {order_column, direction};cardinality-one 或 picked-many lookup 可帶 fallback = {table_id, match, target_column}
  • Lookup 設定建立後不可變更。PATCH columns/{column_id} 只能修改 namedescription;要改 link_fieldtarget_columnpickfallback 或型別,必須刪除並重建欄位。
  • lookup 不可 required、不可有 default_valuemax_length,記錄 payload 的非 null 值會被拒。
  • one link 回純量;many link 回陣列,除非 pick 把它收斂。cardinality-one lookup 與 picked many lookup 一般都可用於計算欄排序/篩選,也可當 formula 運算元;若要當數值 formula 的輸入,lookup 目標必須是數值。加入 fallback 後,該 lookup 不可做 computed filter 或 sort。未帶 pick 的 many lookup 仍然不可篩選、不可排序,也不能當 formula 運算元。
  • 呼叫者完全無權讀取目標表時,值為 null 且欄位標記 restricted: true;逐列 ACL 不可讀時則只遮蔽對應值。
  • pick.order_column 對某位讀者是隱藏欄時,欄位 ACL 會讓整個 picked cell 失效,即使被帶出的 target_column 是可見的 — 因為排名鍵本身就是一種排序 oracle。這就是 picked lookup 可能對非管理者回 null 的原因。
  • 任何 primary 權限拒絕都不會執行 fallback。只有真正 primary null 時,才按 ID 選第一筆 live、可讀的 defaults row;fallback-side 或 $row 輸入受限時會抑制 probe。
  • pick.order_column 是跨表相依:在目標表上刪除它、或跨型別家族改型別,都會像 lookup 的 target_column 一樣被 409 擋下。
  • Defaults-side 的 fallback.match keys、fallback.target_column,以及每個透過 $row 引用的本表欄位也都是相依;刪除或不相容 retype 前,先移除或重建 lookup。

試試看

先用連結與彙總流程精靈建立 link,再到 API Playgroundcolumns.preview 驗證 lookup 的 target_column

Last updated on