JSONB — saqlash, o'qish, yangilash, operatorlar
Muammodan boshlaylik
Mahsulotlar katalogi yozyapsiz. Har bir mahsulotning o'lchamlari, ranglari, texnik xususiyatlari bor. Lekin har xil mahsulot har xil xususiyatlarga ega — televizorning "ekran o'lchami" bor, oyoq kiyimning "o'lcham jadval" bor, kitobning "sahifalar soni" bor.
Har birini alohida ustun qilish mumkin emas — 50 ta ustun, ko'pchiligi NULL. Alohida xususiyatlar jadvali ham murakkab — har bir mahsulot uchun 10-20 ta qator.
Yechim: xususiyatlarni JSON formatida bitta ustunda saqlash. PostgreSQL ning JSONB turi — ana shu uchun.
JSON va JSONB — farqi nima?
PostgreSQL da ikkita JSON turi bor:
JSON JSONB
──────────────────── ────────────────────────────────
Matn sifatida saqlaydi Binary formatda saqlaydi
Yozish tezroq O'qish va qidirish tezroq
Tartib saqlanadi Tartib saqlanmaydi, takror kalitlar o'chadi
Index qo'yib bo'lmaydi GIN index qo'yish mumkin
Amalda deyarli har doim JSONB ishlatiladi. JSON faqat asl yozuvni (tartib, takrorlar) saqlash zarur bo'lganda.
JSONB ustun yaratish
CREATE TABLE mahsulotlar (
id SERIAL PRIMARY KEY,
nomi TEXT NOT NULL,
narx NUMERIC NOT NULL,
xususiyatlar JSONB -- ← JSONB ustun
);
Ma'lumot qo'shish
JSONB ga oddiy JSON qiymati yoziladi:
INSERT INTO mahsulotlar (nomi, narx, xususiyatlar) VALUES
(
'Noutbuk Pro',
8500000,
'{"brend": "Dell", "ram": 16, "ssd": 512, "ranglar": ["qora", "kumush"], "ekran": {"o_lcham": 15.6, "razreshenie": "1920x1080"}}'
),
(
'Simsiz Quloqchin',
1200000,
'{"brend": "Sony", "battery": 30, "ranglar": ["qora", "oq", "ko_k"], "noise_cancelling": true}'
),
(
'Mexanik Klaviatura',
950000,
'{"brend": "Keychron", "switch": "Red", "backlight": true, "ranglar": ["qora"]}'
);
O'qish operatorlari
JSONB dan qiymat olish uchun ikkita asosiy operator:
-> kalit yoki indeks bo'yicha — JSONB qaytaradi
->> kalit yoki indeks bo'yicha — TEXT qaytaradi
Vizual:
xususiyatlar -> 'brend' → "Dell" (JSONB, qo'shtirnoq bilan)
xususiyatlar ->> 'brend' → Dell (TEXT, oddiy matn)
Asosiy qiymat olish
SELECT
nomi,
xususiyatlar -> 'brend' AS brend_jsonb,
xususiyatlar ->> 'brend' AS brend_text,
xususiyatlar ->> 'ram' AS ram
FROM mahsulotlar;
nomi │ brend_jsonb │ brend_text │ ram
-------------------+-------------+------------+------
Noutbuk Pro │ "Dell" │ Dell │ 16
Simsiz Quloqchin │ "Sony" │ Sony │ NULL
Mexanik Klaviatura│ "Keychron" │ Keychron │ NULL
Quloqchin da ram yo'q — NULL qaytadi, xato bermaydi.
Ichma-ich (nested) qiymat olish
-> larni zanjirlab yozish mumkin:
SELECT
nomi,
xususiyatlar -> 'ekran' ->> 'o_lcham' AS ekran_olcham
FROM mahsulotlar;
nomi │ ekran_olcham
-------------------+--------------
Noutbuk Pro │ 15.6
Simsiz Quloqchin │ NULL
Mexanik Klaviatura│ NULL
Massiv elementini olish
SELECT
nomi,
xususiyatlar -> 'ranglar' -> 0 AS birinchi_rang_jsonb,
xususiyatlar -> 'ranglar' ->> 0 AS birinchi_rang_text
FROM mahsulotlar;
nomi │ birinchi_rang_jsonb │ birinchi_rang_text
-------------------+---------------------+--------------------
Noutbuk Pro │ "qora" │ qora
Simsiz Quloqchin │ "qora" │ qora
Mexanik Klaviatura│ "qora" │ qora
#> va #>> — yo'l bilan olish
Chuqur nested qiymat uchun yo'lni massiv sifatida berib, bir qadam bilan olish:
SELECT
nomi,
xususiyatlar #>> '{ekran, o_lcham}' AS ekran_olcham
FROM mahsulotlar;
{ekran, o_lcham} — avval ekran kalitiga, keyin o_lcham kalitiga tush.
Filtrlash
Aniq qiymatga teng
-- brendu Dell bo'lgan mahsulotlar
SELECT nomi FROM mahsulotlar
WHERE xususiyatlar ->> 'brend' = 'Dell';
@> — ichida bor operatori (contains)
JSONB ning eng kuchli operatori. Qiymat ichida berilgan tuzilma bormi yo'qmi tekshiradi:
-- noise_cancelling: true bo'lgan mahsulotlar
SELECT nomi FROM mahsulotlar
WHERE xususiyatlar @> '{"noise_cancelling": true}';
nomi
------------------
Simsiz Quloqchin
-- ranglar ichida "qora" bor mahsulotlar
SELECT nomi FROM mahsulotlar
WHERE xususiyatlar @> '{"ranglar": ["qora"]}';
nomi
--------------------
Noutbuk Pro
Simsiz Quloqchin
Mexanik Klaviatura
@> — GIN index bilan juda tez ishlaydi. Bu operatorsiz qidirish katta jadvalda sekin.
? — kalit bormi
-- "battery" kaliti bor mahsulotlar
SELECT nomi FROM mahsulotlar
WHERE xususiyatlar ? 'battery';
nomi
------------------
Simsiz Quloqchin
-- "battery" yoki "ssd" kalitlaridan biri bor mahsulotlar (?| — birortasi)
SELECT nomi FROM mahsulotlar
WHERE xususiyatlar ?| ARRAY['battery', 'ssd'];
-- "battery" va "noise_cancelling" ikkalasi ham bor (?& — hammasi)
SELECT nomi FROM mahsulotlar
WHERE xususiyatlar ?& ARRAY['battery', 'noise_cancelling'];
Yangilash
Bitta kalit qiymatini o'zgartirish — ||
|| operatori ikki JSONB ni birlashtiradi. Bir xil kalit bo'lsa — o'ngdagisi ustunlik qiladi:
UPDATE mahsulotlar
SET xususiyatlar = xususiyatlar || '{"ram": 32}'
WHERE nomi = 'Noutbuk Pro';
-- ram: 16 → 32 ga o'zgaradi
jsonb_set — aniq kalit yangilash
UPDATE mahsulotlar
SET xususiyatlar = jsonb_set(
xususiyatlar, -- ← asl qiymat
'{ram}', -- ← qaysi kalit
'32' -- ← yangi qiymat (JSONB sifatida)
)
WHERE nomi = 'Noutbuk Pro';
Nested qiymat:
UPDATE mahsulotlar
SET xususiyatlar = jsonb_set(
xususiyatlar,
'{ekran, o_lcham}',
'17.3'
)
WHERE nomi = 'Noutbuk Pro';
Kalit o'chirish — -
UPDATE mahsulotlar
SET xususiyatlar = xususiyatlar - 'battery'
WHERE nomi = 'Simsiz Quloqchin';
Foydali funksiyalar
-- Barcha kalitlarni ro'yxat sifatida
SELECT jsonb_object_keys(xususiyatlar) FROM mahsulotlar WHERE id = 1;
-- JSONB ni jadval ko'rinishiga yoyish
SELECT * FROM jsonb_each_text(
'{"brend": "Dell", "ram": "16", "ssd": "512"}'
);
-- kalit │ qiymat
-- ------+-------
-- brend │ Dell
-- ram │ 16
-- ssd │ 512
-- Massivdagi elementlar sonini hisoblash
SELECT jsonb_array_length(xususiyatlar -> 'ranglar')
FROM mahsulotlar;
Tez-tez uchraydigan xatolar
-> va ->> ni aralashtirib yuborish:
-- ❌ — -> TEXT bilan taqqoslab bo'lmaydi
WHERE xususiyatlar -> 'brend' = 'Dell';
-- ERROR: operator does not exist: jsonb = text
-- ✅ — ->> TEXT qaytaradi
WHERE xususiyatlar ->> 'brend' = 'Dell';
-> JSONB qaytaradi — "Dell" (qo'shtirnoq bilan). ->> TEXT qaytaradi — Dell. Oddiy matn bilan taqqoslashda ->> ishlatiladi.
Raqamli qiymatni TEXT sifatida olish:
-- ❌ — ->> TEXT qaytaradi, raqam sifatida taqqoslab bo'lmaydi
WHERE xususiyatlar ->> 'ram' > 8;
-- ERROR: operator does not exist: text > integer
-- ✅ — CAST qilish kerak
WHERE (xususiyatlar ->> 'ram')::INT > 8;
Xulosa
JSONB — PostgreSQL da tuzilmasi o'zgaruvchan ma'lumotlarni saqlash uchun.
-> kalit bo'yicha JSONB olish
->> kalit bo'yicha TEXT olish
#>> yo'l bo'yicha TEXT olish
@> ichida tuzilma bormi (GIN index bilan tez)
? kalit bormi
|| birlashtirish / kalit yangilash
- kalit o'chirish
JSONB har bir qator uchun har xil tuzilmaga ruxsat beradi — relatsion jadvallarning qattiqligi va JSON ning moslashuvchanligi birga.
Keyingi dars
23-dars: JSONB — GIN index, so'rovlarni tezlashtirish