JSON / JSONB
UQL provides first-class support for JSON/JSONB fields across PostgreSQL, MySQL, and SQLite. Query, update, and sort by nested JSON properties using a consistent, type-safe API — UQL generates dialect-specific SQL automatically.
Entity Setup
Section titled “Entity Setup”Wrap JSONB field types with Json<T> to enable full type safety — IDE autocompletion for dot-notation paths, $merge keys, and $unset keys.
import { Entity, Id, Field, Json } from 'uql-orm';
@Entity()export class Company { @Id() id?: number;
@Field() name?: string;
@Field({ type: 'jsonb' }) kind?: Json<{ public?: number; private?: number }>;
@Field({ type: 'jsonb' }) settings?: Json<{ isArchived?: boolean; theme?: string; locale?: string }>;}Filtering (Dot-Notation)
Section titled “Filtering (Dot-Notation)”Query nested JSON properties using dot-notation paths in $where. All comparison operators are supported.
const companies = await querier.findMany(Company, { $where: { 'settings.isArchived': { $ne: true }, 'settings.theme': 'dark', },});SELECT * FROM "Company"WHERE ("settings"->>'isArchived') IS DISTINCT FROM $1 AND "settings"->>'theme' = $2SELECT * FROM `Company`WHERE JSON_EXTRACT(`settings`, '$.isArchived') <> ? AND JSON_EXTRACT(`settings`, '$.theme') = ?SELECT * FROM `Company`WHERE json_extract(`settings`, '$.isArchived') IS NOT ? AND json_extract(`settings`, '$.theme') = ?Updating ($merge / $unset)
Section titled “Updating ($merge / $unset)”Atomically merge or remove keys in JSON fields directly from update payloads. No need to overwrite the entire JSON value.
$merge — Partial Update
Section titled “$merge — Partial Update”Merge new key-value pairs into an existing JSON field. Existing keys not in $merge are preserved.
await querier.updateOneById(Company, id, { kind: { $merge: { public: 1 } },});UPDATE "Company" SET "kind" = COALESCE("kind", '{}') || $1::jsonb WHERE "id" = $2-- values: ['{"public":1}', id]UPDATE `Company` SET `kind` = JSON_MERGE_PATCH(COALESCE(`kind`, '{}'), ?) WHERE `id` = ?-- values: ['{"public":1}', id]UPDATE `Company` SET `kind` = json_patch(COALESCE(`kind`, '{}'), ?) WHERE `id` = ?-- values: ['{"public":1}', id]$unset — Remove Keys
Section titled “$unset — Remove Keys”Remove specific keys from a JSON field.
await querier.updateOneById(Company, id, { kind: { $unset: ['private'] },});UPDATE "Company" SET "kind" = ("kind") - 'private' WHERE "id" = $1UPDATE `Company` SET `kind` = JSON_REMOVE(`kind`, '$.private') WHERE `id` = ?UPDATE `Company` SET `kind` = json_remove(`kind`, '$.private') WHERE `id` = ?Combined $merge + $unset
Section titled “Combined $merge + $unset”Both operations can be combined in a single update.
await querier.updateOneById(Company, id, { kind: { $merge: { public: 1 }, $unset: ['private'] },});Sorting (Dot-Notation)
Section titled “Sorting (Dot-Notation)”Sort by nested JSON field values using the same dot-notation syntax.
const companies = await querier.findMany(Company, { $sort: { 'kind.public': 'desc' },});SELECT * FROM "Company" ORDER BY "kind"->>'public' DESCSELECT * FROM `Company` ORDER BY JSON_EXTRACT(`kind`, '$.public') DESCSELECT * FROM `Company` ORDER BY json_extract(`kind`, '$.public') DESCSupported Dialects
Section titled “Supported Dialects”All JSON features work across three SQL dialects:
| Feature | PostgreSQL | MySQL | SQLite |
|---|---|---|---|
| Dot-notation filtering | ->>'key' | JSON_EXTRACT() | json_extract() |
$merge | || ::jsonb | JSON_MERGE_PATCH() | json_patch() |
$unset | - 'key' | JSON_REMOVE() | json_remove() |
| Dot-notation sorting | ->>'key' | JSON_EXTRACT() | json_extract() |