ObjectQL
/api/v1/data/*, 뷰, 리포트, AI 도구에서 사용하는 구조화된 쿼리 형식입니다.
ObjectQL
ObjectQL은 데이터 엔진이 사용하는 JSON 쿼리 형식입니다.
/api/v1/data/:object가 받아들이는 형식이며, 뷰가 컴파일되는 대상이고,
리포트가 직렬화되는 형식이며, AI query_data 도구가 생성하는 형식입니다.
두 가지 형태가 있습니다.
- 단순 목록(Simple list) —
where,orderBy,limit,expand등을 쿼리 문자열 파라미터로GET /api/v1/data/:object에 전달합니다. - 고급 쿼리(Advanced query) — 전체 쿼리 본문을
/api/v1/data/:object/query에 POST합니다 (groupBy와aggregations에 필요).
쿼리 형태
{
object: string, // required — target object name
fields?: string[], // projection (default: all visible fields)
where?: FilterCondition, // see Filters
orderBy?: SortNode[], // [{ field, order: 'asc' | 'desc' }]
limit?: number, // page size
offset?: number, // offset pagination
cursor?: string, // cursor pagination (preferred)
expand?: string[], // batch-resolve relation fields
joins?: JoinNode[], // explicit joins (inner | left | right | full)
groupBy?: (string | GroupByNode)[],
aggregations?: AggregationNode[], // sum/avg/count/min/max/...
having?: FilterCondition, // filter after aggregation
distinct?: boolean
}스키마 소스: packages/spec/src/data/query.zod.ts.
필터(Filters)
where는 조건들의 트리입니다. 필드 연산자는
$로 접두됩니다. 논리 결합자($and, $or, $not)는 최상위 레벨에 위치합니다.
비교
| 연산자 | 예시 | 비고 |
|---|---|---|
$eq | { status: { $eq: "open" } } | 같음 |
$ne | { priority: { $ne: "low" } } | 같지 않음 |
$gt, $gte, $lt, $lte | { amount: { $gte: 1000 } } | 비교 |
모든 비교 연산자는 **필드 참조(field reference)**도 받아들여
필드 간 비교를 할 수 있습니다: { 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": "..." }로 삽입할 수 있습니다 — 서버가 쿼리 시점에
평가하는 "현재 기준(now-relative)" 필터에 유용합니다.
정렬
"orderBy": [
{ "field": "priority", "order": "desc" },
{ "field": "created_at", "order": "asc" }
]쿼리 문자열 약식 표기: ?orderBy=-priority,created_at.
페이지네이션
커서(권장). 응답에 nextCursor가 포함됩니다. 이를 다음 요청의
cursor로 다시 전달하세요.
GET /api/v1/data/ticket?limit=50&orderBy=-created_at
→ { items: [...], nextCursor: "eyJ..." }
GET /api/v1/data/ticket?limit=50&cursor=eyJ...오프셋. 더 단순하지만 대용량 테이블에서는 성능이 저하됩니다.
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
}각 티켓을 단순 ID가 아니라 assignee와 customer.account가
중첩 객체로 구체화된 형태로 반환합니다.
조인(Joins)
메타데이터 그래프 외부에서 임시 조인을 수행하려면 다음과 같이 합니다.
"joins": [
{ "type": "left", "object": "user", "as": "u", "on": "assignee_id = u.id" }
]type: inner | left | right | full. 조인된 테이블은 as
별칭을 통해 where, orderBy, aggregations에서 접근할 수 있습니다.
집계(Aggregation)
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
}함수: count, sum, avg, min, max, count_distinct,
array_agg, string_agg.
날짜 단위(시간 버킷 기준 group-by용):
day | week | month | quarter | year.
Distinct
{ "object": "ticket", "fields": ["status"], "distinct": true }검색
searchable: true 필드 전반에 대한 전체 텍스트 검색은
GET /api/v1/search?q=...&object=ticket에서 제공됩니다. 객체별 점수 산정 규칙은
객체 스펙에서 구성합니다.
ObjectQL이 사용되는 곳
GET /api/v1/data/:object— 쿼리 문자열 형태POST /api/v1/data/:object/query— 전체 본문, 집계 지원- 뷰 정의(
filter,sort) — ObjectQL로 컴파일됨 - 리포트 — ObjectQL로 직렬화됨
- AI
query_data도구 — 승인 큐를 위한 ObjectQL 본문을 생성함
함께 보기
- REST API — ObjectQL을 사용하는 엔드포인트
- 필드 타입 — 쿼리 가능한 항목
- CEL —
$cel필터 내부에서 사용하는 표현식 언어 @objectstack/spec/data/query.zod.ts— 공식 스키마