IlmHamroh
JavaScript Full-stack/27-qism. Ma'lumotlar bazasi chuqur: Postgres, ORM, Mongo, Redis1/65-dars26 daqiqa
Mundarija (38)

PostgreSQL JSONB: operatorlar, jsonpath, JSON_TABLE va GIN indeks

Qisqacha: JSONB — Postgres ustuni ichida JSON hujjat saqlash turi. Ichidan qiymat olish -> (JSON) va ->> (matn) bilan, qidirish @> ("shu bo'lak bormi") bilan, o'zgartirish jsonb_set va || bilan bo'ladi. U butunligicha o'qiladigan moslashuvchan ma'lumot (masalan, foydalanuvchi sozlamalari) uchun yaxshi. Filtrlanadigan, saralanadigan yoki statistikasi kerak maydon esa oddiy ustun bo'lgani ma'qul — kanon o'lchovida farq 70 baravargacha chiqdi.

Bu darsda

  • ->, ->>, #>, #>> farqini va natija turini (jsonb yoki text) aytasiz.
  • @>, ?, ?|, ?& bilan JSONB ichidan qidirasiz.
  • jsonb_set, ||, -, #- bilan hujjatni o'zgartirasiz va ikki jim tuzoqni chetlab o'tasiz.
  • jsonpath (@?, jsonb_path_query) va JSON_TABLE bilan JSON'ni jadvalga aylantirasiz.
  • GIN indeksining ikki turini taniysiz va "JSONB yoki ustun" qarorini o'lchov bilan qabul qilasiz.
  • vazifalar bazasiga foydalanuvchi sozlamalarini qo'shamiz (holat 01).

Oldin bilishingiz kerak: PostgreSQL ma'lumot turlari, Modellash naqshlari, Indeks turlari: GIN, GiST, BRIN, EXPLAIN ANALYZE'ni o'qish.

1. Nega bu kerak?

26-qismni keyset sahifalash bilan tugatdik: vazifalar bazasi tayyor, API undan o'qiydi. Endi 27-qism — bazani chuqurroq ishlatish. Birinchi talab frontend'dan keladi.

i18n darslarida o'quvchi interfeys tilini tanlay oladigan qilgan edik: lotin, kirill, rus, ingliz. Yana mavzu (yorug' yoki qorong'i) va bildirishnomalar bor. Hozir bular brauzerda saqlanadi. Aziz telefonida "qorong'i" ni tanlasa, kompyuterida baribir yorug' ko'radi. Sozlamalar serverda, foydalanuvchi bilan birga saqlanishi kerak.

Har sozlama uchun alohida ustun ochish mumkin: til, mavzu, email_bildirishnoma, telegram_bildirishnoma... Lekin ertaga frontend yangi tajribaviy sozlama qo'shadi — har safar ALTER TABLE va migratsiya. Sozlamalar esa doim butunligicha o'qiladi: sahifa ochilganda hammasi bir obyekt bo'lib frontend'ga ketadi.

O'xshatish: dori qutichasi. Har dori uchun shkafda alohida tortma ochmaysiz — hammasi bitta qutida, kerak bo'lganda qutini ochib olasiz. Lekin dorixona o'z omborini bunday saqlamaydi: u yerda har dori tartiblangan javonda, chunki "qaysi dorining muddati o'tdi?" degan savolga tez javob kerak. JSONB — quticha. Oddiy ustunlar — javon. Bu darsda ikkalasi qachon kerakligini o'lchab ko'ramiz.

Modellash naqshlari darsida jsonb + CHECK ni EAV o'rniga ko'rgan edik. Endi uni to'liq o'rganamiz: operatorlar, o'zgartirish, qidiruv, indeks.

2. Sozlamalar ustuni

2.1 Kanon fayli

Kanon sql/101-sozlamalar-jsonb.sql — kod o'zgarmagan, faqat qatorlarni telefon ekraniga sig'ishi uchun bo'ldik va izohlarni qisqartirdik:

sql
ALTER TABLE foydalanuvchilar
  ADD COLUMN sozlamalar jsonb NOT NULL DEFAULT '{}'::jsonb;

-- Faqat obyekt; ma'lum kalitlarning qiymati tekshiriladi,
-- noma'lum kalitlar — ruxsat (oldinga moslik)
ALTER TABLE foydalanuvchilar
  ADD CONSTRAINT foydalanuvchilar_sozlamalar_check CHECK (
  jsonb_typeof(sozlamalar) = 'object'
  AND (NOT sozlamalar ? 'til'
       OR sozlamalar->>'til' IN ('uz-Latn', 'uz-Cyrl', 'ru', 'en'))
  AND (NOT sozlamalar ? 'mavzu'
       OR sozlamalar->>'mavzu' IN ('yorug', 'qorongi', 'tizim'))
  AND (NOT sozlamalar ? 'bildirishnoma'
       OR jsonb_typeof(sozlamalar->'bildirishnoma') = 'object')
);

CREATE INDEX foydalanuvchilar_sozlamalar_idx
  ON foydalanuvchilar USING gin (sozlamalar jsonb_path_ops);

Uch qaror:

  1. NOT NULL DEFAULT '{}' — sozlamasi yo'q foydalanuvchida ham bo'sh obyekt bor. Ilova NULL ni alohida tekshirmaydi.
  2. CHECK — JSONB "hamma narsa kiraveradi" degani emas. Ma'lum kalitlar (til, mavzu) ruxsat etilgan qiymatlardan biri bo'lishi shart. Noma'lum kalit esa ruxsat: frontend yangi sozlama qo'shsa, baza uni rad etmaydi. Bu oldinga moslik (forward compatibility) — eski sxema yangi ilovaga xalaqit bermaydi.
  3. GIN indeksi — keyinroq «GIN indeksi» bo'limida o'lchaymiz.

NOT sozlamalar ? 'til' OR … — "kalit yo'q bo'lsa — mayli, bor bo'lsa — to'g'ri qiymat". ? operatorini bir oz pastda ko'ramiz.

2.2 Namuna ma'lumot

102-namuna-sozlamalar.sql 8 foydalanuvchidan 6 tasiga sozlama yozadi. Holat 01 bazasida (bu darsdagi so'rovlarni o'z PostgreSQL 17.6 klasterimizda ishga tushirdik; kanon PostgreSQL 18.6 da chiqish bir xil, farqi bo'lsa — aytamiz):

sql
SELECT id, ism, sozlamalar FROM foydalanuvchilar ORDER BY id;
text
 id |        ism         |                                         sozlamalar
----+--------------------+--------------------------------------------------------------------------------------------
  1 | Aziz Karimov       | {"til": "uz-Latn", "mavzu": "qorongi", "bildirishnoma": {"email": true, "telegram": true}}
  2 | Dilnoza Rahimova   | {"til": "uz-Cyrl", "mavzu": "yorug", "bildirishnoma": {"email": false}}
  3 | Sardor Tursunov    | {"mavzu": "qorongi", "tajriba": {"yangi_royxat": true}}
  4 | Madina Yusupova    | {"til": "ru", "mavzu": "tizim"}
  5 | Javohir Olimov     | {}
  6 | Gulnora Saidova    | {"til": "uz-Latn", "bildirishnoma": {"email": true, "telegram": false}}
  7 | Bekzod Nazarov     | {"til": "en", "mavzu": "qorongi", "bildirishnoma": {"email": true}}
  8 | Shahnoza Ergasheva | {}
(8 rows)

Nimaga qarang: Sardorda (3) tajriba degan noma'lum kalit bor — CHECK uni o'tkazdi. Madinada (4) bildirishnoma umuman yo'q. Javohir va Shahnozada — bo'sh obyekt. Kalitlar alifbo tartibida emas, balki uzunligi bo'yicha, keyin alifbo bo'yicha turibdi: jsonb kalitlarni o'zi tartiblaydi (Ma'lumot turlari darsida ko'rganmiz). Bu ikkilik ichki tartib, unga tayanmang.

3. Ichiga kirish: ->, ->>, #>, #>>

3.1 To'rt operator

Operator Nima qaytaradi Misol
-> JSONB (kalit yoki massiv indeksi bo'yicha) s->'til' → "uz-Latn"
->> matn (text) s->>'til' → uz-Latn
#> JSONB (yo'l bo'yicha) s#>'{bildirishnoma,email}' → true
#>> matn (yo'l bo'yicha) s#>>'{bildirishnoma,email}' → true

Kanon so'rovi (uzun qator bo'lingan):

sql
\pset null '(null)'
SELECT id,
       sozlamalar->'til'  AS til_jsonb,
       sozlamalar->>'til' AS til_text,
       sozlamalar#>'{bildirishnoma,email}'  AS email_jsonb,
       sozlamalar#>>'{bildirishnoma,email}' AS email_text
FROM foydalanuvchilar ORDER BY id;
text
Null display is "(null)".
 id | til_jsonb | til_text | email_jsonb | email_text
----+-----------+----------+-------------+------------
  1 | "uz-Latn" | uz-Latn  | true        | true
  2 | "uz-Cyrl" | uz-Cyrl  | false       | false
  3 | (null)    | (null)   | (null)      | (null)
  4 | "ru"      | ru       | (null)      | (null)
  5 | (null)    | (null)   | (null)      | (null)
  6 | "uz-Latn" | uz-Latn  | true        | true
  7 | "en"      | en       | true        | true
  8 | (null)    | (null)   | (null)      | (null)
(8 rows)

\pset null '(null)' — psql'ga "NULL ni ko'rinadigan qilib yoz" deydi (psql chuqur); birinchi qatorda psql shu sozlamani tasdiqlaydi. Ikki narsaga qarang:

  1. -> natijasi qo'shtirnoqli: "uz-Latn" — bu JSON satri. ->> natijasi qo'shtirnoqsiz — oddiy Postgres matni.
  2. Kalit yo'q bo'lsa — xato emas, NULL. Madinada (4) bildirishnoma yo'q, natija (null).

#> ning yo'li — massiv ko'rinishidagi matn: '{bildirishnoma,email}' — "avval bildirishnoma, uning ichida email". Xuddi shuni zanjir bilan ham yozish mumkin: sozlamalar->'bildirishnoma'->>'email'. Massiv elementiga raqam bilan murojaat qilinadi, 0 dan boshlab; manfiy raqam — oxiridan:

sql
SELECT '{"teglar":["#uy","#ish"]}'::jsonb->'teglar'->0 AS birinchi,
       '{"teglar":["#uy","#ish"]}'::jsonb->'teglar'->>-1 AS oxirgi;
text
 birinchi | oxirgi
----------+--------
 "#uy"    | #ish
(1 row)

Diqqat: JSON massivida indeks 0 dan, Postgres massivida esa (keyingi darsda) 1 dan boshlanadi. Bir bazada ikki xil qoida.

3.2 Tur tuzog'i: ->> doim matn

->> hamma narsani matnga aylantiradi — true ham, 5 ham. Shuning uchun uni mantiqiy qiymat bilan solishtirib bo'lmaydi:

sql
SELECT ism FROM foydalanuvchilar
WHERE sozlamalar->'bildirishnoma'->>'email' = true;
text
ERROR:  operator does not exist: text = boolean
LINE 2: WHERE sozlamalar->'bildirishnoma'->>'email' = true;
                                                    ^
HINT:  No operator matches the given name and argument types. You might need to add explicit type casts.

"text = boolean operatori mavjud emas". Postgres matnni mantiqiy qiymatga o'zi aylantirmaydi. ^ belgisi aynan = ostida turibdi: muammo tenglikda, uning chap va o'ng tomoni turlarida. HINT ham shuni aytadi: "aniq tur o'girishi (cast) qo'shishingiz kerak bo'lishi mumkin".

Ikki to'g'ri yo'l bor. Birinchisi — matnni o'zingiz boolean ga o'girish (::boolean). Ikkinchisi — JSONB'ni JSONB bilan solishtirish:

sql
SELECT ism FROM foydalanuvchilar
WHERE (sozlamalar#>>'{bildirishnoma,email}')::boolean
ORDER BY id;
SELECT ism FROM foydalanuvchilar
WHERE sozlamalar->'bildirishnoma'->'email' = 'true'
ORDER BY id;
text
       ism
-----------------
 Aziz Karimov
 Gulnora Saidova
 Bekzod Nazarov
(3 rows)

       ism
-----------------
 Aziz Karimov
 Gulnora Saidova
 Bekzod Nazarov
(3 rows)

Ikkinchi so'rovda 'true' — JSONB literal (Postgres uni chap tomonga qarab jsonb deb tushunadi). Natija bir xil. Lekin keyingi bo'limdagi @> bundan ham qulayroq.

Tekshirib ko'ring: sozlamalar->>'til' = 'ru' ishlaydimi? sozlamalar->'til' = 'ru' chi?

Javob

Birinchisi ishlaydi: ->> matn qaytaradi, 'ru' ham matn. Ikkinchisida -> JSONB qaytaradi, 'ru' esa JSONB sifatida o'qiladi — lekin ru to'g'ri JSON emas (JSON satri qo'shtirnoqda bo'ladi: '"ru"'). Postgres invalid input syntax for type json xatosini beradi. Qoida: JSONB bilan solishtirsangiz — o'ng tomon ham to'g'ri JSON bo'lsin.

4. Qidirish: @> va kalit operatorlari

4.1 @> — "shu bo'lak ichida bormi"

@> (contains) chapdagi hujjat o'ngdagi bo'lakni o'z ichiga oladimi — shuni tekshiradi. Bo'lak ichma-ich bo'lishi ham mumkin:

sql
SELECT ism FROM foydalanuvchilar
WHERE sozlamalar @> '{"mavzu": "qorongi"}' ORDER BY id;
SELECT ism FROM foydalanuvchilar
WHERE sozlamalar @> '{"bildirishnoma": {"email": true}}'
ORDER BY id;
text
       ism
-----------------
 Aziz Karimov
 Sardor Tursunov
 Bekzod Nazarov
(3 rows)

       ism
-----------------
 Aziz Karimov
 Gulnora Saidova
 Bekzod Nazarov
(3 rows)

Ikkinchi so'rov "bildirishnoma ichida email true bo'lganlar". Turlar bilan muammo yo'q: true — JSON mantiqiy qiymati, cast kerak emas. @> ni GIN indeks qo'llaydi — u JSONB qidiruvining asosiy operatori.

4.2 ?, ?|, ?& — kalit bormi

sql
SELECT ism,
       sozlamalar ? 'til' AS til_bor,
       sozlamalar ?| array['til','mavzu'] AS biri,
       sozlamalar ?& array['til','mavzu'] AS ikkalasi
FROM foydalanuvchilar ORDER BY id;
text
        ism         | til_bor | biri | ikkalasi
--------------------+---------+------+----------
 Aziz Karimov       | t       | t    | t
 Dilnoza Rahimova   | t       | t    | t
 Sardor Tursunov    | f       | t    | f
 Madina Yusupova    | t       | t    | t
 Javohir Olimov     | f       | f    | f
 Gulnora Saidova    | t       | t    | f
 Bekzod Nazarov     | t       | t    | t
 Shahnoza Ergasheva | f       | f    | f
(8 rows)
Operator Savol
? Bu kalit bormi?
?| Ro'yxatdagi kalitlardan kamida bittasi bormi?
?& Hammasi bormi?

Ular faqat yuqori darajadagi kalitlarga qaraydi: sozlamalar ? 'email' — false, chunki email bildirishnoma ichida. Ichkaridagi kalit uchun: sozlamalar->'bildirishnoma' ? 'email'.

Tekshirib ko'ring: Kalit bor, lekin qiymati JSON null: '{"til": null}'. ? 'til' nima qaytaradi? ->>'til' chi?

Javob

? 'til' — true: kalit bor. ->>'til' — SQL NULL. Ya'ni ->> natijasidagi NULL "kalit yo'q" ham, "kalit bor, qiymati null" ham bo'lishi mumkin. Farq muhim bo'lsa — ? bilan tekshiring. Bu farq kanon CHECK'ida kutilmagan teshik ochadi — «Ko'p uchraydigan xatolar» bo'limida ko'rsatamiz.

5. O'zgartirish: jsonb_set, ||, -, #-

5.1 jsonb_set — bitta qiymatni almashtirish

jsonb_set(hujjat, yo'l, yangi_qiymat) — yangi hujjat qaytaradi, unda yo'l bo'yicha qiymat almashgan. Bu bo'limdagi har misol o'z BEGIN … ROLLBACK i ichida — bazani buzmaymiz, har blokni alohida ishga tushirsa bo'ladi:

sql
BEGIN;
UPDATE foydalanuvchilar
SET sozlamalar = jsonb_set(sozlamalar,
      '{bildirishnoma,telegram}', 'true')
WHERE id = 2 RETURNING sozlamalar;
ROLLBACK;
text
BEGIN
                                        sozlamalar
-------------------------------------------------------------------------------------------
 {"til": "uz-Cyrl", "mavzu": "yorug", "bildirishnoma": {"email": false, "telegram": true}}
(1 row)

UPDATE 1
ROLLBACK

Dilnozaning bildirishnoma obyektiga telegram qo'shildi, email joyida qoldi. Uchinchi argument — JSONB: 'true', satr bo'lsa '"qorongi"' (ichki qo'shtirnoq bilan).

5.2 Birinchi jim tuzoq: oraliq kalit yo'q bo'lsa

Endi xuddi shunday Madinaga (4) email bildirishnomasini yoqamiz:

sql
BEGIN;
UPDATE foydalanuvchilar
SET sozlamalar = jsonb_set(sozlamalar,
      '{bildirishnoma,email}', 'true')
WHERE id = 4 RETURNING sozlamalar;
ROLLBACK;
text
BEGIN
           sozlamalar
---------------------------------
 {"til": "ru", "mavzu": "tizim"}
(1 row)

UPDATE 1
ROLLBACK

UPDATE 1 — "bitta qator yangilandi". Lekin hujjat o'zgarmadi. Madinada bildirishnoma obyekti yo'q, jsonb_set esa faqat oxirgi kalitni yarata oladi, oraliqdagisini emas. Xato ham, ogohlantirish ham yo'q. Bu kanon topilmasi: ilovada "saqlandi" xabari chiqadi, foydalanuvchiga esa email hech qachon kelmaydi.

To'g'ri yo'l — oraliq obyektni o'zingiz ta'minlash: coalesce(…, '{}') "yo'q bo'lsa — bo'sh obyekt" (NULL mantiqi darsidagi coalesce):

sql
BEGIN;
UPDATE foydalanuvchilar
SET sozlamalar = jsonb_set(sozlamalar, '{bildirishnoma}',
      coalesce(sozlamalar->'bildirishnoma', '{}')
      || '{"email": true}')
WHERE id = 4 RETURNING sozlamalar;
ROLLBACK;
text
BEGIN
                            sozlamalar
-------------------------------------------------------------------
 {"til": "ru", "mavzu": "tizim", "bildirishnoma": {"email": true}}
(1 row)

UPDATE 1
ROLLBACK

Endi ishladi. Bu yerda || ni ishlatdik — u nima qilishini hozir ko'ramiz.

5.3 Ikkinchi jim tuzoq: || sayoz birlashtiradi

|| ikki obyektni birlashtiradi: o'ngdagi kalitlar chapdagini bosib ketadi. Aziz email'ni o'chirmoqchi:

sql
BEGIN;
UPDATE foydalanuvchilar
SET sozlamalar = sozlamalar
      || '{"bildirishnoma": {"email": false}}'
WHERE id = 1 RETURNING sozlamalar;
ROLLBACK;
text
BEGIN
                                sozlamalar
---------------------------------------------------------------------------
 {"til": "uz-Latn", "mavzu": "qorongi", "bildirishnoma": {"email": false}}
(1 row)

UPDATE 1
ROLLBACK

email false bo'ldi — lekin telegram yo'qoldi! || faqat yuqori darajada birlashtiradi (sayoz — shallow): bildirishnoma kaliti butunligicha yangi obyekt bilan almashdi. Ichkariga kirmaydi. Shuning uchun yuqoridagi to'g'ri yo'lda || ni aynan bildirishnoma obyektining o'ziga qo'lladik.

Diqqat: Frontend ko'pincha "o'zgargan qismini" yuboradi: {"bildirishnoma": {"email": false}}. Uni sozlamalar || $1 bilan yozish — boshqa ichki sozlamalarni o'chirish. Ichma-ich obyektlar uchun jsonb_set yoki ilovada chuqur birlashtirish kerak.

5.4 Kalitni o'chirish: - va #-

sql
BEGIN;
UPDATE foydalanuvchilar SET sozlamalar = sozlamalar - 'tajriba'
WHERE id = 3 RETURNING sozlamalar;
UPDATE foydalanuvchilar
SET sozlamalar = sozlamalar #- '{bildirishnoma,telegram}'
WHERE id = 6 RETURNING sozlamalar;
ROLLBACK;
text
BEGIN
      sozlamalar
----------------------
 {"mavzu": "qorongi"}
(1 row)

UPDATE 1
                      sozlamalar
------------------------------------------------------
 {"til": "uz-Latn", "bildirishnoma": {"email": true}}
(1 row)

UPDATE 1
ROLLBACK

- — yuqori darajadagi kalitni, #- — yo'l bo'yicha ichkaridagisini o'chiradi. Sardorning tajribaviy kaliti ketdi, Gulnorada faqat email qoldi. ROLLBACK — hamma o'zgarishlar bekor, baza avvalgidek.

5.5 CHECK himoya qiladi

Moslashuvchanlik chegarasiz emas. Kanon CHECK'i noto'g'ri qiymatni ham, obyekt bo'lmagan hujjatni ham rad etadi:

sql
UPDATE foydalanuvchilar SET sozlamalar = '{"til": "uz"}'
WHERE id = 5;
UPDATE foydalanuvchilar SET sozlamalar = '[1,2]' WHERE id = 5;
text
ERROR:  new row for relation "foydalanuvchilar" violates check constraint "foydalanuvchilar_sozlamalar_check"
DETAIL:  Failing row contains (5, javohir@example.com, Javohir Olimov, 2026-09-21 06:30:00+00, 6, {"til": "uz"}).
ERROR:  new row for relation "foydalanuvchilar" violates check constraint "foydalanuvchilar_sozlamalar_check"
DETAIL:  Failing row contains (5, javohir@example.com, Javohir Olimov, 2026-09-21 06:30:00+00, 6, [1, 2]).

"Yangi qator foydalanuvchilar_sozlamalar_check cheklovini buzadi". DETAIL — rad etilgan qatorning to'liq ko'rinishi. uz ruxsat ro'yxatida yo'q (uz-Latn bo'lishi kerak), [1,2] esa massiv, obyekt emas.

Tekshirib ko'ring: Nega kanon CHECK'da til ro'yxati bor-u, bildirishnoma.email ning turi (boolean) tekshirilmaydi?

Javob

Kanon faqat "obyekt bo'lsin" deb tekshiradi — bu murosa. Har ichki kalitni CHECK'da yozish mumkin (jsonb_typeof(sozlamalar#>'{bildirishnoma,email}') = 'boolean'), lekin CHECK tez o'sadi va o'qilmay qoladi. Batafsil tekshiruv API'da — Zod sxemasi bilan; baza esa eng muhim qoidalarni oxirgi himoya sifatida ushlaydi. Bu ikki qatlamli himoya.

6. jsonpath: JSON ichida so'rov tili

6.1 @? va jsonb_path_query

jsonpath — JSON hujjat ichidan yo'l va shart bilan qidirish tili (SQL standartining bir qismi). $ — hujjatning o'zi, .kalit — ichkariga, [*] — massivning hamma elementlari, ? (…) — filtr, @ — filtr ichidagi joriy element:

sql
SELECT ism,
       jsonb_path_query_first(sozlamalar,
         '$.bildirishnoma.email') AS email
FROM foydalanuvchilar
WHERE sozlamalar @? '$.bildirishnoma ? (@.email == true)'
ORDER BY id;
text
       ism       | email
-----------------+-------
 Aziz Karimov    | true
 Gulnora Saidova | true
 Bekzod Nazarov  | true
(3 rows)

@? — "shu yo'l biror natija beradimi". jsonb_path_query_first — birinchi natijani qaytaradi. jsonpath ichida tenglik == (JS'dagidek), SQL'dagi = emas.

Massiv bilan kuchi ko'proq ko'rinadi. Hujjatda teglar ro'yxati, har birida soni:

sql
SELECT jsonb_path_query(
  '{"teglar": [{"nom":"#ish","soni":5},
               {"nom":"#uy","soni":2},
               {"nom":"#sport","soni":9}]}',
  '$.teglar[*] ? (@.soni > 3).nom');
text
 jsonb_path_query
------------------
 "#ish"
 "#sport"
(2 rows)

"Teglar ichidan soni 3 dan katta bo'lganlarining nomi" — bitta ifoda. jsonb_path_query har natijani alohida qator qilib qaytaradi.

6.2 JSON_TABLE — JSON'dan jadval (PostgreSQL 17+)

JSON_TABLE JSON hujjatni oddiy jadvalga aylantiradi: siz ustunlarni va har birining yo'lini yozasiz. PostgreSQL 17 da qo'shilgan — eski versiyalarda yo'q:

sql
\pset null '(null)'
SELECT f.ism, jt.*
FROM foydalanuvchilar f,
     JSON_TABLE(f.sozlamalar, '$' COLUMNS (
       til text PATH '$.til' DEFAULT 'uz-Latn' ON EMPTY,
       mavzu text PATH '$.mavzu',
       email boolean PATH '$.bildirishnoma.email'
     )) jt
ORDER BY f.id;
text
Null display is "(null)".
        ism         |   til   |  mavzu  | email
--------------------+---------+---------+--------
 Aziz Karimov       | uz-Latn | qorongi | t
 Dilnoza Rahimova   | uz-Cyrl | yorug   | f
 Sardor Tursunov    | uz-Latn | qorongi | (null)
 Madina Yusupova    | ru      | tizim   | (null)
 Javohir Olimov     | uz-Latn | (null)  | (null)
 Gulnora Saidova    | uz-Latn | (null)  | t
 Bekzod Nazarov     | en      | qorongi | t
 Shahnoza Ergasheva | uz-Latn | (null)  | (null)
(8 rows)

Nimaga qarang: til hech qayerda (null) emas. DEFAULT 'uz-Latn' ON EMPTY — "yo'l hech narsa topmasa, shu qiymat". Sardor, Javohir va Shahnoza tilni tanlamagan — ilova ularga sukut bo'yicha lotin interfeysini ko'rsatadi, so'rov ham xuddi shunday. email ustuni esa haqiqiy boolean — endi uni WHERE email yoki count(*) FILTER (WHERE email) bilan ishlatish mumkin. JSON bilan emas, odatiy jadval bilan ishlaganday.

f, JSON_TABLE(f.sozlamalar …) — har foydalanuvchi qatori uchun uning hujjatidan jadval yasaladi. Bu LATERAL g'oyasi: o'ngdagi ifoda chapdagi qatorni ko'radi.

7. JSON'ni yasash: API javobi

Teskari yo'nalish ham kerak: oddiy ustunlardan JSON yasash. API uchun bu qulay — bazaning o'zi tayyor obyekt qaytaradi:

sql
SELECT json_build_object('id', id, 'ism', ism,
                         'sozlamalar', sozlamalar)
FROM foydalanuvchilar WHERE id = 7;
text
                                                    json_build_object
--------------------------------------------------------------------------------------------------------------------------
 {"id" : 7, "ism" : "Bekzod Nazarov", "sozlamalar" : {"til": "en", "mavzu": "qorongi", "bildirishnoma": {"email": true}}}
(1 row)

json_build_object argumentlarni juft-juft oladi: kalit, qiymat, kalit, qiymat. json turi kalitlar orasiga " : " qo'yadi. Ixchamroq natija uchun jsonb_build_object bor (Agregatlar darsidagi jsonb_agg bilan tanishsiz). json va jsonb farqi Ma'lumot turlari darsida: json matnni aynan saqlaydi, jsonb ikkilik ko'rinishda, takror kalitning oxirgisini qoldiradi va kalitlarni tartiblaydi. Saqlash uchun deyarli doim jsonb.

8. GIN indeksi

8.1 Ikki turi

JSONB ustuniga oddiy B-tree indeks ma'nosiz — u butun hujjatni bitta qiymat deb biladi. Indeks turlari darsidagi GIN esa hujjatni bo'laklarga ajratadi. Keyin har bo'lak qaysi qatorlarda borligini eslab qoladi — kitob oxiridagi alifbo ko'rsatkichi kabi. JSONB uchun uning ikki varianti bor:

Variant Qaysi operatorlar Hajm (kanon, 1 mln qator)
jsonb_ops (sukut) @>, ?, ?|, ?&, @?, @@ 9 056 kB
jsonb_path_ops faqat @>, @?, @@ 4 472 kB

Kanon jsonb_path_ops ni tanladi: ikki baravar kichik, "kimda qorong'i mavzu" kabi @> savollari uchun yetarli.

8.2 Indeks qaysi so'rovga ishlaydi

8 qatorli jadvalda planner indeksga qaramaydi — butun jadvalni o'qish arzon. Indeks ishlatilishi mumkinmi, shuni ko'rish uchun ketma-ket o'qishni vaqtincha "qimmat" qilamiz (EXPLAIN ANALYZE'ni o'qish):

sql
SET enable_seqscan = off;
EXPLAIN (COSTS OFF) SELECT ism FROM foydalanuvchilar
WHERE sozlamalar @> '{"mavzu": "qorongi"}';
EXPLAIN (COSTS OFF) SELECT ism FROM foydalanuvchilar
WHERE sozlamalar->>'mavzu' = 'qorongi';
RESET enable_seqscan;
text
SET
                            QUERY PLAN
-------------------------------------------------------------------
 Bitmap Heap Scan on foydalanuvchilar
   Recheck Cond: (sozlamalar @> '{"mavzu": "qorongi"}'::jsonb)
   ->  Bitmap Index Scan on foydalanuvchilar_sozlamalar_idx
         Index Cond: (sozlamalar @> '{"mavzu": "qorongi"}'::jsonb)
(4 rows)

                          QUERY PLAN
--------------------------------------------------------------
 Seq Scan on foydalanuvchilar
   Filter: ((sozlamalar ->> 'mavzu'::text) = 'qorongi'::text)
(2 rows)

RESET

Birinchi so'rov foydalanuvchilar_sozlamalar_idx dan foydalandi (Bitmap Index Scan). Ikkinchisi — ma'nosi bir xil, lekin ->> va = bilan yozilgan — Seq Scan qoldi, hatto taqiqlangan bo'lsa ham. GIN ->> tengligini umuman tushunmaydi. Kanon PostgreSQL 18.6 da ikkinchi rejada yana bir qator chiqadi — Disabled: true ("bu tugun taqiqlangan edi, boshqa yo'l yo'q"); PG 18 EXPLAIN'ining yangiligi, ma'nosi o'sha.

Qoida: GIN indeksli JSONB ustunga @> bilan so'rov yozing. Bu darsdagi eng amaliy qoida.

9. JSONB yoki ustun: o'lchov

9.1 Kanon tajribasi

Kanon bir xil ma'lumotni ikki shaklda saqladi: 1 mln qator JSONB hujjat (j_sozlama) va xuddi shu qiymatlar oddiy ustunlarda (u_sozlama). So'rov — "tili ru va Telegram bildirishnomasi yoqilganlar soni" (24 928 qator, 2.5 %). Har variant EXPLAIN ANALYZE bilan (kanon o'lchovi (IlmHamroh, 2026-10): PostgreSQL 18.6, Docker, bitta o'lchov):

Bir xil savol, to'rt xil saqlash
  • JSONB, indekssizParallel Seq Scan119,6 ms
  • JSONB + GIN path_opsBitmap, 12 658 sahifa171,9 ms
  • JSONB + ifoda indeksiB-tree (s->>'til', ...)38,2 ms
  • Oddiy ustunlar + B-treeIndex Only Scan1,7 ms

Manba: IlmHamroh kanon o'lchovi, 2026-10-24: PostgreSQL 18.6, Docker (WSL2), 1 mln qator

Nimaga qarang: GIN indeksi bu savolda indekssiz variantdan ham sekinroq chiqdi. Sabab — so'rov selektiv emas: 24 928 qator jadvalning 16 000 sahifasidan 12 658 tasiga sochilgan. Indeks qatorlarni tez topdi, lekin keyin baribir deyarli hamma sahifani o'qishga to'g'ri keldi. Halol izoh: GIN o'lchovida 100 ms diskdan o'qishga ketgan (kesh sovuq edi) — bu raqam bitta o'lchov, mutlaq qiymatga emas, tartibga qarang.

Oddiy ustunlar + B-tree — 1.7 ms, 70 baravar tez: indeksning o'zida javob bor, jadvalga umuman bormaydi (Index Only Scan, Covering indekslar).

Hajm ham: JSONB jadval 125 MB, ustunli jadval 47 MB. Har JSONB qatorida kalit nomlari ("bildirishnoma", "telegram") qaytadan yoziladi; ustunda nom bir marta — jadval sxemasida.

9.2 Planner JSONB ichini bilmaydi

Eng yashirin farq. Statistika va planner darsida ko'rdik: planner har ustun qiymatlarining taqsimotini biladi. JSONB ichidagi kalitlarniki — yo'q. Kanon "mavzusi qorong'i va email yoqilgan" qatorlarni sanadi (COSTS ON — planner taxmini ko'rinsin). Ikki qatorda rows= (planner taxmini) va actual rows= (haqiqat) ni solishtiring:

text
 Gather  (cost=1000.00..26625.00 rows=2500 width=98) (actual rows=99873.00 loops=1)
text
 Seq Scan on u_sozlama  (cost=0.00..18566.00 rows=100502 width=17) (actual rows=99873.00 loops=1)

JSONB'da planner 2 500 qator kutdi, haqiqatda 99 873 — 40 baravar xato. Ustunlarda taxmin 100 502 — deyarli aniq. Planner kichik son kutsa, katta JOIN uchun noto'g'ri usul tanlaydi va so'rov sekinlashadi. 2 500 ma'lumotdan olinmagan: JSONB ichidagi qiymatlar haqida statistika yo'q, shuning uchun planner o'zining sukut koeffitsientlari bilan "taxminan" sanaydi. (CREATE STATISTICS ifodalar uchun ham bor — Statistika va planner; yoki ifoda indeksi, u o'z statistikasini yig'adi.)

9.3 Qaror

flowchart TD
  A["Yangi maydon"] --> B{"WHERE, ORDER BY yoki<br/>JOIN'da ishlatiladimi?"}
  B -- "ha" --> U["Oddiy ustun"]
  B -- "yo'q" --> C{"FK yoki qat'iy<br/>tur kerakmi?"}
  C -- "ha" --> U
  C -- "yo'q" --> D{"Butunligicha<br/>o'qiladimi?"}
  D -- "ha" --> J["JSONB + CHECK"]
  D -- "yo'q" --> U

Kanon xulosasi: filtrlanadigan, statistikasi kerak maydon — ustun. JSONB — butun obyekt sifatida o'qiladigan, tez-tez o'zgaradigan sozlamalar. Agar JSONB ichidagi maydon bo'yicha tez-tez qidira boshlasangiz — bu uni ustunga chiqarish vaqti kelganining belgisi (yoki ifoda indeksi — 38 ms, oraliq yechim).

10. Ko'p uchraydigan xatolar

1. ->> ni boolean yoki son bilan solishtirish. operator does not exist: text = boolean. ->> doim matn. Tuzatish: ::boolean / ::int yoki @>.

2. jsonb_set oraliq kalitsiz. Xato yo'q, UPDATE 1, lekin hujjat o'zgarmaydi. Tuzatish: coalesce(s->'ota', '{}') || '{"kalit": …}' bilan ota obyektni ta'minlang yoki natijani RETURNING bilan tekshiring.

3. || bilan ichma-ich obyektni yangilash. Qo'shni ichki kalitlar o'chadi. Tuzatish: jsonb_set bilan aniq yo'lga yozing.

4. GIN bor, so'rov ->> bilan. Indeks ishlamaydi, Seq Scan. Tuzatish: @> yoki ifoda indeksi ((s->>'til')).

5. "Hamma narsa JSONB'da". Filtrlanadigan maydonlar hujjat ichida: jadval 2.7 baravar katta, planner adashadi, FK qo'yib bo'lmaydi. Tuzatish: qidiriladigan maydonni ustunga chiqaring.

6. JSON null CHECK'dan o'tib ketadi. Biz o'z klasterimizda sinadik — kanon CHECK'i shu qiymatni qabul qildi:

sql
BEGIN;
UPDATE foydalanuvchilar SET sozlamalar = '{"til": null}'
WHERE id = 5
RETURNING sozlamalar, sozlamalar ? 'til' AS kalit_bor;
ROLLBACK;
text
BEGIN
  sozlamalar   | kalit_bor
---------------+-----------
 {"til": null} | t
(1 row)

UPDATE 1
ROLLBACK

Nega? Kalit bor, shuning uchun NOT sozlamalar ? 'til' — false. ->>'til' esa NULL, va NULL IN ('uz-Latn', …) — NULL. false OR NULL — NULL. CHECK esa NULL natijani "buzilmadi" deb hisoblaydi (NULL mantiqi). Ilova uchun {"til": null} — g'alati holat: kalit bor, til yo'q. Tuzatish: shartni jsonb_typeof(sozlamalar->'til') = 'string' AND … bilan kuchaytirish. Halol aytamiz: kanon bu teshikni yopmagan va yopmaydi — 101 qo'llangan, kanon sxemasi qotgan, ilova (API va Zod) til: null yubormaydi. O'z loyihangizda tuzatish yangi migratsiya faylida bo'ladi (Loyiha qadamidagi qoida); 4-mashqda shuni ROLLBACK ichida sinab ko'rasiz. mavzu da ham xuddi shu teshik bor.

11. Mashqlar

Mashqlar kurs/mashqlar/27/01-jsonb/ da. Hammasi holat 01 bazasida, o'zgartiradiganlari BEGIN … ROLLBACK ichida; yechimlar tekshirilgan (biz ishga tushirdik, PostgreSQL 17.6).

1-mashq (oson)

Telegram bildirishnomasi yoqilgan (true) foydalanuvchilarning ismini chiqaring. Gulnorada telegram bor, lekin false — u chiqmasligi kerak. Ishora: «@> — "shu bo'lak ichida bormi"» bo'limi, ichma-ich bo'lak.

Yechim
sql
SELECT ism FROM foydalanuvchilar
WHERE sozlamalar @> '{"bildirishnoma": {"telegram": true}}';
text
     ism
--------------
 Aziz Karimov
(1 row)

Faqat Aziz. @> qiymatni ham tekshiradi — Gulnoraning telegram: false bo'lagi {"telegram": true} ni o'z ichiga olmaydi. Bu so'rov GIN indeksidan foydalana oladi.

2-mashq (o'rta)

Madina (4) va Gulnora (6) uchun Telegram bildirishnomasini yoqing. Gulnoraning email: true qiymati saqlanib qolishi shart, Madinada esa bildirishnoma obyekti umuman yo'q. Bitta UPDATE bilan, natijani RETURNING id, sozlamalar->'bildirishnoma' bilan ko'rsating, oxirida ROLLBACK. Ishora: «Birinchi jim tuzoq» bo'limidagi coalesce(…, '{}') || … naqshi.

Yechim
sql
BEGIN;
UPDATE foydalanuvchilar
SET sozlamalar = jsonb_set(sozlamalar, '{bildirishnoma}',
      coalesce(sozlamalar->'bildirishnoma', '{}')
      || '{"telegram": true}')
WHERE id IN (4, 6)
RETURNING id, sozlamalar->'bildirishnoma' AS bildirishnoma;
ROLLBACK;
text
BEGIN
 id |           bildirishnoma
----+-----------------------------------
  4 | {"telegram": true}
  6 | {"email": true, "telegram": true}
(2 rows)

UPDATE 2
ROLLBACK

Madinaga yangi obyekt yaratildi, Gulnorada email joyida qoldi va telegram false dan true ga o'zgardi. Oddiy jsonb_set(s, '{bildirishnoma,telegram}', 'true') Madinada jim hech narsa qilmasdi, s || '{"bildirishnoma": {"telegram": true}}' esa Gulnoraning email ini o'chirardi. (RETURNING qatorlari id tartibida chiqdi, lekin UPDATE tartibni kafolatlamaydi — kerak bo'lsa saralash keyingi SELECT da.)

3-mashq (qiyin)

Har interfeys tili bo'yicha nechta foydalanuvchi bor va ulardan nechtasi email bildirishnoma oladi — bitta so'rov. Tilni tanlamaganlar uz-Latn hisoblansin, email kaliti yo'qlar — false. Natija: til, email_oladi, jami, til bo'yicha alifbo tartibida. Ishora: JSON_TABLE va DEFAULT … ON EMPTY («JSON_TABLE — JSON'dan jadval» bo'limi), count(*) FILTER (WHERE …) — Agregatlar.

Yechim
sql
SELECT jt.til,
       count(*) FILTER (WHERE jt.email) AS email_oladi,
       count(*) AS jami
FROM foydalanuvchilar f,
  JSON_TABLE(f.sozlamalar, '$' COLUMNS (
    til text PATH '$.til' DEFAULT 'uz-Latn' ON EMPTY,
    email boolean PATH '$.bildirishnoma.email'
      DEFAULT false ON EMPTY)) jt
GROUP BY jt.til ORDER BY jt.til;
text
   til   | email_oladi | jami
---------+-------------+------
 en      |           1 |    1
 ru      |           0 |    1
 uz-Cyrl |           0 |    1
 uz-Latn |           2 |    5
(4 rows)

uz-Latn — 5 ta: Aziz va Gulnora tanlagan, uchtasi sukut bo'yicha. Email olayotganlar ikkita (Aziz, Gulnora). JSON_TABLE dan keyin bu oddiy GROUP BY — JSON bilan ishlash tugadi, jadval bilan ishlash boshlandi. PostgreSQL 16 va eskida JSON_TABLE yo'q: u yerda coalesce(s->>'til', 'uz-Latn') va coalesce((s#>>'{bildirishnoma,email}')::boolean, false) bilan yoziladi.

4-mashq (qiyin)

«Ko'p uchraydigan xatolar» dagi JSON null teshigini yoping — til va mavzu uchun. Kanon cheklovini o'chirib, xuddi shu nom bilan kuchliroq cheklov qo'shing (bitta ALTER TABLE ichida DROP CONSTRAINT …, ADD CONSTRAINT …). Keyin Javohirga (5) '{"til": null}' yozib ko'ring — rad etilishi kerak. Hammasi BEGIN … ROLLBACK ichida: bu mashq, migratsiya emas. Ishora: kalit bor bo'lsa, qiymat avval jsonb_typeof(…) = 'string' bo'lsin, keyin ro'yxatda.

Yechim
sql
BEGIN;
ALTER TABLE foydalanuvchilar
  DROP CONSTRAINT foydalanuvchilar_sozlamalar_check,
  ADD CONSTRAINT foydalanuvchilar_sozlamalar_check CHECK (
  jsonb_typeof(sozlamalar) = 'object'
  AND (NOT sozlamalar ? 'til'
       OR (jsonb_typeof(sozlamalar->'til') = 'string'
           AND sozlamalar->>'til'
               IN ('uz-Latn', 'uz-Cyrl', 'ru', 'en')))
  AND (NOT sozlamalar ? 'mavzu'
       OR (jsonb_typeof(sozlamalar->'mavzu') = 'string'
           AND sozlamalar->>'mavzu' IN ('yorug', 'qorongi', 'tizim')))
  AND (NOT sozlamalar ? 'bildirishnoma'
       OR jsonb_typeof(sozlamalar->'bildirishnoma') = 'object')
);
UPDATE foydalanuvchilar SET sozlamalar = '{"til": null}'
WHERE id = 5;
ROLLBACK;
text
BEGIN
ALTER TABLE
ERROR:  new row for relation "foydalanuvchilar" violates check constraint "foydalanuvchilar_sozlamalar_check"
DETAIL:  Failing row contains (5, javohir@example.com, Javohir Olimov, 2026-09-21 06:30:00+00, 6, {"til": null}).
ROLLBACK

ALTER TABLE o'tdi — demak mavjud 8 qatorning hammasi yangi shartga mos (Postgres yangi cheklovni qo'shishda har qatorni tekshiradi). {"til": null} endi rad etildi: jsonb_typeof JSON null uchun 'null' qaytaradi, 'null' = 'string' — false, false AND … — false, NULL emas. Haqiqiy loyihada bu blok ROLLBACK siz, yangi raqamli migratsiya faylida turadi.

12. Loyiha qadami

Holat 64 (26-qism yakuni) → holat 01. 27-qismning birinchi o'zgarishi — ikki fayl:

  • sql/101-sozlamalar-jsonb.sql — ustun, CHECK va GIN indeks (to'liq matni «Kanon fayli» bo'limida);
  • sql/102-namuna-sozlamalar.sql — 6 foydalanuvchiga namuna sozlamalar.

Nega 101, 015 emas? 27-qism fayllari 101 dan boshlanadi: 001–014 — 26-qismniki, ular orasiga keyin yana fayl qo'shilsa, raqamlar to'qnashmasin. Namuna fayli (102) — kanon qoidasi bo'yicha: nomida namuna bor fayllar prodakshn bazasiga qo'llanmaydi.

102 ning boshi (kanon, qatorlar bo'lingan):

sql
UPDATE foydalanuvchilar SET sozlamalar = s.j::jsonb
FROM (VALUES
  ('aziz@example.com',
   '{"til": "uz-Latn", "mavzu": "qorongi",
     "bildirishnoma": {"email": true, "telegram": true}}'),
  ('dilnoza@example.com',
   '{"til": "uz-Cyrl", "mavzu": "yorug",
     "bildirishnoma": {"email": false}}'),
  -- … yana 4 foydalanuvchi: madina, gulnora, sardor, bekzod
) AS s(email, j)
WHERE foydalanuvchilar.email = s.email;

To'liq faylda 6 qator — «Namuna ma'lumot» bo'limidagi jadvaldagi qiymatlar. Qo'llash (26-qismdagi kabi, har fayl bitta tranzaksiyada):

bash
psql -X -1 -v ON_ERROR_STOP=1 \
  -d postgres://postgres@127.0.0.1:5499/vazifalar \
  -f sql/101-sozlamalar-jsonb.sql
psql -X -1 -v ON_ERROR_STOP=1 \
  -d postgres://postgres@127.0.0.1:5499/vazifalar \
  -f sql/102-namuna-sozlamalar.sql

Tekshiruv: «Namuna ma'lumot» bo'limidagi SELECT xuddi o'sha 8 qatorni bersin. Commit:

bash
git add sql/101-sozlamalar-jsonb.sql sql/102-namuna-sozlamalar.sql
M='db: foydalanuvchi sozlamalari — jsonb, CHECK va GIN indeks'
M+=' (101, 102-namuna)'
git commit -m "$M"

26-qismdagi qoida 27 da ham amal qiladi: qo'llangan fayl o'zgartirilmaydi. «Ko'p uchraydigan xatolar» dagi JSON null teshigini yopmoqchi bo'lsangiz — 101 ni tahrirlamaysiz, yangi fayl yozasiz (ALTER TABLE … DROP CONSTRAINT …, ADD CONSTRAINT …). Sabab: 101 allaqachon boshqa bazalarda (hamkasbingizda, serverda) qo'llangan — u yerda tahrirlangan fayl hech qachon qayta ishlamaydi va bazalar bir-biridan farqlanib ketadi.

API hali sozlamalarni o'qimaydi — bu ustun hozircha faqat bazada. Uni ORM orqali API'ga ulash — Prisma darslarida (ORM, query builder va raw SQL dan boshlab).

13. Real ishda

  • Sozlamalar, metama'lumot, integratsiya javoblari. To'lov tizimi (Click, Payme) qaytargan to'liq javobni jsonb da saqlash — keyin "nima kelgan edi?" degan savolga javob bor. Lekin summa, holat, sana — alohida ustunlarda.
  • Audit jadvallari. Kanon vazifa_tarixi ning eski va yangi ustunlari aynan jsonb (Soft delete va tarix).
  • ORM'larda. Prisma Json turi, Drizzle jsonb() — ichida shu tur; filtrlash imkoniyatlari esa cheklangan, murakkab so'rov uchun xom SQL kerak bo'ladi (Prisma: raw SQL va TypedSQL darsida ko'ramiz).
  • MongoDB bilan solishtirish. "Hujjat saqlash kerak — Mongo olaylik" degan fikr ko'p uchraydi. Ko'pincha Postgres'ning jsonb i yetarli; farqlarni Mongo darslarida o'lchaymiz.
  • Intervyuda: "json va jsonb farqi?", "JSONB'ni qanday indekslaysiz?", "Qachon JSONB ishlatmaysiz?" — javobda @> + GIN, ifoda indeksi va planner statistikasini tilga oling.

Xulosa

  • -> JSONB, ->> matn qaytaradi; ->> ni boolean bilan solishtirish — xato, ::boolean yoki @> kerak.
  • @> — JSONB qidiruvining asosiy operatori, GIN uni qo'llaydi; ->> tengligini GIN qo'llamaydi.
  • jsonb_set oraliq kalit yo'q bo'lsa jim hech narsa qilmaydi; || sayoz — ichki obyektni butunlay almashtiradi.
  • jsonpath (@?, jsonb_path_query) — JSON ichida filtr; JSON_TABLE (PG 17+) — JSON'dan oddiy jadval.
  • CHECK bilan JSONB "nazoratli moslashuvchan" bo'ladi: ma'lum kalitlar tekshiriladi, noma'lumlari o'tadi.
  • Kanon o'lchovi: ustun + B-tree 1.7 ms, JSONB + GIN 171.9 ms; jadval 47 va 125 MB; planner JSONB ichida 40 baravar adashdi. Filtrlanadigan maydon — ustun.

Keyingi dars: Massivlar, range, domain va maxsus turlar — Postgres'ning boy tur tizimi: massivlar, vaqt oraliqlari va kesishmaydigan bronlar, o'z turingiz (DOMAIN) va registrga befarq matn.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
PostgreSQL JSONB: operatorlar, jsonpath, JSONTABLE va GIN indeks — IlmHamroh