Sorting
$sort orders by any field of the entity, by a JSON path inside one, and by a joined relation’s field. A direction is 'asc' / 1 or 'desc' / -1, and keys order by in the order you write them:
const posts = await pool.findMany(Post, { $select: { title: true, publishedAt: true }, $sort: { publishedAt: 'desc', title: 'asc' },});ORDER BY "publishedAt" DESC, "title"Where nulls land
Section titled “Where nulls land”A column is nullable in UQL unless it says nullable: false, and each engine has its own idea of where those nulls belong:
| Engine | Unqualified asc puts nulls |
|---|---|
| PostgreSQL, CockroachDB, Neon, PGlite, Bun SQL | last |
| SQLite, libSQL, Turso, D1, MySQL, MariaDB, SQL Server | first |
| MongoDB | first (a missing field counts as null) |
So the same query answers in a different order depending on where it runs. Say which one you want, and it reads the same everywhere:
const posts = await pool.findMany(Post, { $sort: { publishedAt: 'descNullsLast' },});The four placements are ascNullsFirst, ascNullsLast, descNullsFirst and descNullsLast. They work anywhere a direction does: a field, a JSON path, a joined relation’s field, a populated relation’s own $sort, and an aggregate’s.
Each engine gets there its own way, and the result is identical:
ORDER BY "publishedAt" DESC NULLS LASTORDER BY `publishedAt` IS NULL, `publishedAt` DESCORDER BY CASE WHEN [publishedAt] IS NULL THEN 1 ELSE 0 END, [publishedAt] DESCMongoDB has no placement at all, so the pipeline flags each row and orders by the flag first, then takes the flag back off before you see the document.
Next steps
Section titled “Next steps”- Relations: sorting by a joined field, and a populated collection’s own
$sort. - Counting: ordering parents by how many rows a relation holds.
- Full-text search and semantic search: ranking by relevance or vector distance.