ObjectOS
參考

ObjectQL

/api/v1/data/*、檢視、報表和 AI 工具使用的結構化查詢格式。

ObjectQL 是資料引擎消費的 JSON 查詢格式。它是 /api/v1/data/:object 接受的內容、檢視編譯的目標、報表的序列化形式,以及 AI query_data 工具產生的內容。

兩種形態:

  • 簡單列表 —— 將 whereorderBylimitexpand 等作為查詢字串引數傳給 GET /api/v1/data/:object
  • 高階查詢 —— 將完整查詢體 POST 到 /api/v1/data/:object/querygroupByaggregations 必需)。

查詢形狀

{
  object:        string,                  // 必填 —— 目标对象名
  fields?:       string[],                // 投影(默认:所有可见字段)
  where?:        FilterCondition,         // 见 Filters
  orderBy?:      SortNode[],              // [{ field, order: 'asc' | 'desc' }]
  limit?:        number,                  // 页大小
  offset?:       number,                  // offset 分页
  cursor?:       string,                  // cursor 分页(优先)
  expand?:       string[],                // 批量解析关系字段
  joins?:        JoinNode[],              // 显式 join(inner | left | right | full)
  groupBy?:      (string | GroupByNode)[],
  aggregations?: AggregationNode[],       // sum/avg/count/min/max/...
  having?:       FilterCondition,         // 聚合后过滤
  distinct?:     boolean
}

Schema 原始碼:packages/spec/src/data/query.zod.ts

過濾器

where 是條件樹。欄位運算子以 $ 為字首;邏輯組合器($and$or$not)位於頂層。

比較

運算子示例說明
$eq{ status: { $eq: "open" } }相等
$ne{ priority: { $ne: "low" } }不等
$gt$gte$lt$lte{ amount: { $gte: 1000 } }比較

所有比較運算子也接受欄位引用用於跨欄位比較:{ end_at: { $gt: { $field: "start_at" } } }

集合與區間

運算子示例
$in{ status: { $in: ["new","open"] } }
$nin{ owner_id: { $nin: ["u_1","u_2"] } }
$between{ created_at: { $between: ["2026-01-01","2026-02-01"] } }

字串

運算子示例說明
$contains{ subject: { $contains: "refund" } }大小寫不敏感
$notContains{ notes: { $notContains: "test" } }
$startsWith{ email: { $startsWith: "@" } }
$endsWith{ email: { $endsWith: "@acme.com" } }

Null 與存在性

運算子示例
$null{ closed_at: { $null: true } }
$exists{ external_id: { $exists: false } }

邏輯組合器

{
  "$and": [
    { "status": { "$eq": "open" } },
    {
      "$or": [
        { "priority": { "$in": ["high", "urgent"] } },
        { "due_at":   { "$lt": { "$cel": "now()" } } }
      ]
    }
  ]
}

CEL 表示式可通過 { "$cel": "..." } 嵌入 —— 對伺服器在查詢時求值的"相對當前時間"過濾器有用。

排序

"orderBy": [
  { "field": "priority", "order": "desc" },
  { "field": "created_at", "order": "asc" }
]

查詢字串簡寫:?orderBy=-priority,created_at

分頁

Cursor(推薦)。 響應中包含 nextCursor;下次請求時作為 cursor 傳回。

GET /api/v1/data/ticket?limit=50&orderBy=-created_at
→ { items: [...], nextCursor: "eyJ..." }

GET /api/v1/data/ticket?limit=50&cursor=eyJ...

Offset。 更簡單但在大表上劣化。

GET /api/v1/data/ticket?limit=50&offset=200

執行時通過 ObjectSpec.maxPageSize 限制每個物件的 limit(預設 200)。

關係 —— expand

expand 批次解析外部索引鍵以避免 N+1。

{
  "object": "support_ticket",
  "expand": ["assignee", "customer.account"],
  "limit": 20
}

返回的每條 ticket 中 assigneecustomer.account 被物化為巢狀物件,而非僅 ID。

Join

用於後設資料圖之外的臨時 join:

"joins": [
  { "type": "left", "object": "user", "as": "u", "on": "assignee_id = u.id" }
]

typeinner | left | right | full。被 join 的表通過 as 別名在 whereorderByaggregations 中可用。

聚合

POST /api/v1/data/:object/query

{
  "object": "order",
  "where": { "status": { "$ne": "cancelled" } },
  "groupBy": [
    "customer_id",
    { "field": "created_at", "dateGranularity": "month" }
  ],
  "aggregations": [
    { "function": "sum",   "field": "amount", "alias": "total_sales" },
    { "function": "count", "alias": "order_count" }
  ],
  "having": { "total_sales": { "$gt": 10000 } },
  "orderBy": [{ "field": "total_sales", "order": "desc" }],
  "limit": 25
}

函式: countsumavgminmaxcount_distinctarray_aggstring_agg

日期粒度(用於時間分桶 group-by): day | week | month | quarter | year

Distinct

{ "object": "ticket", "fields": ["status"], "distinct": true }

搜尋

searchable: true 欄位的全文搜尋通過 GET /api/v1/search?q=...&object=ticket 暴露。每物件評分規則在物件 spec 上配置。

ObjectQL 出現的位置

  • GET /api/v1/data/:object —— 查詢字串形式
  • POST /api/v1/data/:object/query —— 完整請求體,支援聚合
  • 檢視定義(filtersort)—— 編譯為 ObjectQL
  • 報表 —— 序列化為 ObjectQL
  • AI query_data 工具 —— 為審批佇列生成 ObjectQL 請求體

參見

On this page