Skip to content

URL Query Syntax

Experimental

CRUD over HTTP is experimental. APIs may change at any moment.

Overview

The CRUD endpoints parse URL query strings using @uniqu/url into the Uniquery canonical format. This page documents the full syntax for filtering, sorting, pagination, and projection via URLs.

Comparison Operators

URL SyntaxOperatorExampleResult
=$eqstatus=active{ status: 'active' }
!=$nestatus!=deleted{ status: { $ne: 'deleted' } }
>$gtage>25{ age: { $gt: 25 } }
>=$gteage>=18{ age: { $gte: 18 } }
<$ltprice<100{ price: { $lt: 100 } }
<=$lteprice<=99{ price: { $lte: 99 } }
~=$regexname~=/^Jo/i{ name: { $regex: '/^Jo/i' } }

Set Operators

IN

role{Admin,Editor}

Result: { role: { $in: ['Admin', 'Editor'] } }

NOT IN

status!{Draft,Deleted}

Result: { status: { $nin: ['Draft', 'Deleted'] } }

Between

25<age<35

Result: { age: { $gt: 25, $lt: 35 } }

25<=age<=35

Result: { age: { $gte: 25, $lte: 35 } }

Exists

$exists=phone,email

Result: { phone: { $exists: true }, email: { $exists: true } }

$!exists=deletedAt

Result: { deletedAt: { $exists: false } }

Logical Operators

AND (&)

age>=18&status=active

Result: { age: { $gte: 18 }, status: 'active' }

OR (^)

role=admin^role=moderator

Result: { $or: [{ role: 'admin' }, { role: 'moderator' }] }

Precedence

& binds tighter than ^:

age>25^score>550&status=VIP

Result: { $or: [{ age: { $gt: 25 } }, { score: { $gt: 550 }, status: 'VIP' }] }

Parentheses

Override precedence with ():

(age>25^score>550)&status=VIP

Result: { $and: [{ $or: [{ age: { $gt: 25 } }, { score: { $gt: 550 } }] }, { status: 'VIP' }] }

NOT (!())

!(status=deleted)

Result: { $not: { status: 'deleted' } }

Control Keywords

Control keywords start with $ and configure query behavior:

KeywordAliasesExampleDescription
$select--$select=name,emailInclude only listed fields
$select--$select=-passwordExclude listed fields
$order$sort$order=-createdAt,nameSort (prefix - for descending)
$limit$top$limit=20Max results
$skip--$skip=40Skip N results
$count--$countReturn count instead of data
$search--$search=hello worldFull-text search term
$index--$index=my_search_idxNamed search index
$page--$page=3Page number (for /pages endpoint)
$size--$size=25Items per page (for /pages endpoint)

$select Modes

  • Include-only: $select=name,email produces ['name', 'email'] (array form)
  • Exclude-only: $select=-password,-secret produces { password: 0, secret: 0 } (object form)

Avoid mixed mode

Mixing includes and excludes (e.g. $select=name,-password) produces an object map like { name: 1, password: 0 }. The interpretation of mixed projection depends on the database adapter and may lead to unexpected results. Stick to either include-only or exclude-only in a single query.

$order / $sort

Prefix a field name with - for descending order:

$order=-createdAt,name

Result: { $sort: { createdAt: -1, name: 1 } }

Literal Types

SyntaxParsed TypeExamples
Bare numbernumber42, -3.14
Leading zerostring007, 00
true / falsebooleanflag=true
nullnulldeleted=null
'quoted'stringname='John Doe'
Bare wordstringstatus=active

Complete Examples

Simple filter with sorting

GET /todos/query?completed=false&$sort=-createdAt&$limit=10

Find incomplete todos, newest first, max 10.

GET /todos/pages?$search=important&$page=2&$size=20&$sort=-priority

Search for "important", page 2, 20 per page, sorted by priority.

Complex filter

GET /users/query?age>=18&age<=30&role{Admin,Editor}&$select=id,name,email&$order=name

Users aged 18--30 who are Admin or Editor, include only id/name/email, sorted by name.

Count query

GET /todos/query?completed=true&$count

Returns the count of completed todos (number, not array).

Excluding fields

GET /users/query?$select=-password,-secret

All users, excluding password and secret fields.

See Also

Released under the ISC License.