INTEGRITY Dokumentace

Dotazování JSON

D1 nabízí vestavěnou podporu pro dotazování a parsování dat JSON uložených v databázi. To vám umožňuje:

Jednou z největších výhod přímého parsování JSON v D1 je, že přímo snižuje počet zpátečních cest (dotazů) do databáze. Omezuje případy, kdy musíte objekt JSON načíst do aplikace (1), zpracovat ho a poté zapsat zpět (2).

Díky tomu můžete data dotazovat přesněji a zmenšit výslednou sadu, kterou vaše aplikace musí dále zpracovávat a filtrovat.

Typy

Data JSON jsou uložena jako TEXT sloupec v D1. Typy JSON se řídí stejnými pravidla pro převod typů jako D1 obecně, včetně:

Podporované funkce

Následující tabulka popisuje funkce JSON zabudované do D1 a příklady jejich použití.

Funkce Popis Příklad
json(json) Ověří, že zadaný řetězec je JSON, a vrátí minifikovanou verzi tohoto objektu JSON. json('{"hello":["world" ,"there"] }') vrací {"hello":["world","there"]}
json_array(value1, value2, value3, ...) Vrátí pole JSON z hodnot. json_array(1, 2, 3) vrací [1, 2, 3]
json_array_length(json) - json_array_length(json, path) Vrátí délku pole JSON json_array_length('{"data":["x", "y", "z"]}', '$.data') vrací 3
json_extract(json, path) Extrahujte hodnotu (hodnoty) na dané cestě pomocí $.path.to.value syntaxe. json_extract('{"temp":"78.3", "sunset":"20:44"}', '$.temp') vrací "78.3"
json -> path Extrahujte hodnotu (hodnoty) na dané cestě pomocí syntaxe cesty a vraťte ji jako JSON.
json ->> path Extrahujte hodnotu (hodnoty) na dané cestě pomocí syntaxe cesty a vraťte ji jako typ SQL.
json_insert(json, path, value) Vloží hodnotu na zadanou cestu. Existující hodnotu nepřepíše.
json_object(label1, value1, ...) Přijímá dvojice (klíč, hodnota) a vrací JSON objekt. json_object('temp', 45, 'wind_speed_mph', 13) vrací {"temp":45,"wind_speed_mph":13}
json_patch(target, patch) Používá JSON MergePatch přístup ke sloučení poskytnutého patche do cílového objektu JSON.
json_remove(json, path, ...) Odstraní klíč a hodnotu na zadané cestě. json_remove('[60,70,80,90]', '$[0]') vrací 70,80,90]
json_replace(json, path, value) Vloží hodnotu na zadanou cestu. Existující hodnotu přepíše, ale pokud klíč neexistuje, nový nevytvoří.
json_set(json, path, value) Vloží hodnotu na zadanou cestu. Existující hodnotu přepíše.
json_type(json) - json_type(json, path) Vrátí typ zadané hodnoty nebo hodnoty na zadané cestě. Vrátí jednu z těchto možností: null, true, false, integer, real, text, array, nebo object. json_type('{"temperatures":[73.6, 77.8, 80.2]}', '$.temperatures') vrací array
json_valid(json) Vrátí 0 (false) pro neplatný JSON a 1 (true) pro platný JSON. json_valid({invalid:json})vrací0\
json_quote(value) Převede zadanou hodnotu SQL na její reprezentaci ve formátu JSON. json_quote('[1, 2, 3]') vrací [1,2,3]
json_group_array(value) Vrátí zadanou hodnotu (hodnoty) jako pole JSON.
json_each(value) - json_each(value, path) Vrátí každý prvek objektu jako samostatný řádek. Prochází pouze objekt na nejvyšší úrovni.
json_tree(value) - json_tree(value, path) Vrátí každý prvek objektu jako samostatný řádek. Prochází celý objekt.

SQLite Rozšíření JSON, na kterém D1 staví, obsahuje další příklady použití.

Zpracování chyb

Funkce JSON vrátí malformed JSON chybu při práci s daty, která nejsou JSON nebo nejsou platným JSON. D1 považuje za platný JSON RFC 7159 odpovídá standardu.

V následujícím příkladu volání json_extract nad řetězcem (neplatný JSON) způsobí, že dotaz vrátí malformed JSON chyba:

SELECT json_extract('not valid JSON: just a string', '$')

Tím se vrátí chyba:

ERROR 9015: SQL engine error: query error: Error code 1: SQL error or missing database (malformed
  JSON)`

Generované sloupce

podpora D1 pro generované sloupce umožňuje vytvářet dynamické sloupce, které se generují na základě hodnot jiných sloupců, včetně extrahovaných nebo vypočítaných hodnot z dat JSON.

Tyto sloupce lze dotazovat stejně jako kterýkoli jiný sloupec a mohou mít indexy na nich definované. Pokud máte data JSON, která často dotazujete a filtrujete, může vytvoření generovaného sloupce a indexu výrazně zlepšit výkon dotazů.

Pokud chcete například definovat sloupec na základě hodnoty uvnitř většího objektu JSON, použijte AS klíčové slovo kombinované s Funkce JSON ke generování typovaného sloupce:

CREATE TABLE some_table (
    -- other columns omitted
    raw_data TEXT -- JSON: {"measurement":{"aqi":[21,42,58],"wind_mph":"13","location":"US-NY"}}
    location AS (json_extract(raw_data, '$.measurement.location')) STORED
)

Viz Generované sloupce a dozvíte se více o generování sloupců.

Příklad použití

Extrahování hodnot

V D1 existují tři způsoby, jak z objektu JSON extrahovat hodnotu:

-> a ->> operátory fungují obdobně jako stejné operátory v PostgreSQL a MySQL/MariaDB.

Uvažujme následující objekt JSON ve sloupci s názvem sensor_reading, můžete z něj hodnoty extrahovat přímo.

{
    "measurement": {
        "temp_f": "77.4",
        "aqi": [21, 42, 58],
        "o3": [18, 500],
        "wind_mph": "13",
        "location": "US-NY"
    }
}
-- Extract the temperature value
json_extract(sensor_reading, '$.measurement.temp_f')-- returns "77.4" as TEXT
-- Extract the maximum PM2.5 air quality reading
sensor_reading -> '$.measurement.aqi[3]' -- returns 58 as a JSON number
-- Extract the o3 (ozone) array in full
sensor_reading -\-> '$.measurement.o3' -- returns '[18, 500]' as TEXT

Zjištění délky pole

Délku pole JSON můžete zjistit dvěma způsoby:

  1. Voláním json_array_length(value) přímo
  2. Voláním json_array_length(value, path) k určení cesty k poli uvnitř objektu nebo vnějšího pole.

Vezměme si například následující objekt JSON uložený ve sloupci s názvem login_history, můžete přímo získat počet posledních přihlášení:

{
    "user_id": "abc12345",
    "previous_logins": ["2023-03-31T21:07:14-05:00", "2023-03-28T08:21:02-05:00", "2023-03-28T05:52:11-05:00"]
}
json_array_length(login_history, '$.previous_logins') --> returns 3 as an INTEGER

Můžete také použít json_array_length jako predikát ve složitějším dotazu, například WHERE json_array_length(some_column, '$.path.to.value') >= 5.

Vloží hodnotu do existujícího objektu

Hodnotu do existujícího objektu nebo pole JSON můžete vložit pomocí json_insert(). Například pokud máte TEXT sloupec nazvaný login_history v users tabulku obsahující následující objekt:

{"history": ["2023-05-13T15:13:02+00:00", "2023-05-14T07:11:22+00:00", "2023-05-15T15:03:51+00:00"]}

Chcete-li přidat nové časové razítko do history pole v rámci našeho login_history sloupec napište dotaz podobný tomuto:

UPDATE users
SET login_history = json_insert(login_history, '$.history[#]', '2023-05-15T20:33:06+00:00')
WHERE user_id = 'aba0e360-1e04-41b3-91a0-1f2263e1e0fb'

Zadejte tři argumenty pro json_insert:

  1. Název sloupce obsahujícího JSON, který chcete upravit.
  2. Cesta ke klíči v objektu, který chcete upravit.
  3. Hodnota JSON, kterou chcete vložit. Pomocí [#] říká json_insert pro připojení na konec pole.

Pro nahrazení existující hodnoty použijte json_replace(), který přepíše existující dvojici klíč-hodnota, pokud již existuje. Chcete-li hodnotu nastavit bez ohledu na to, zda již existuje, použijte json_set().

Rozbalení polí pro dotazy IN

Použijte json_each k rozbalení pole do více řádků. To se hodí při sestavování WHERE column IN (?) dotaz nad více hodnotami. Pokud byste například chtěli aktualizovat seznam uživatelů podle jejich celočíselného id, použijte json_each k vrácení tabulky, kde je každá hodnota sloupcem s názvem value:

UPDATE users
SET last_audited = '2023-05-16T11:24:08+00:00'
WHERE id IN (SELECT value FROM json_each('[183183, 13913, 94944]'))

Tím by se extrahovala pouze value sloupec z tabulky vrácené json_each, přičemž každý řádek představuje ID uživatelů, která jste předali jako pole.

json_each ve skutečnosti vrací tabulku s více sloupci, z nichž nejdůležitější jsou:

V tomto příkladu SELECT * FROM json_each('[183183, 13913, 94944]') by vrátil tabulku podobnou té níže:

key|value|type|id|fullkey|path
0|183183|integer|1|$[0]|$
1|13913|integer|2|$[1]|$
2|94944|integer|3|$[2]|$

Můžete použít json_each hodnotou D1 Workers Binding API ve Workeru vytvořením příkazu a použitím JSON.stringify k předání pole jako vázaný parametr:

const stmt = context.env.DB
    .prepare("UPDATE users SET last_audited = ? WHERE id IN (SELECT value FROM json_each(?1))")
const resp = await stmt.bind(
    "2023-05-16T11:24:08+00:00",
    JSON.stringify([183183, 13913, 94944])
    ).run()

Tím by se aktualizovaly pouze řádky ve vaší users tabulku, kde id odpovídá jedné ze tří zadaných možností.