12-bo‘lim
JSONB
json va jsonb farqi, qiymat olish operatorlari, ichma-ich yo'l, jsonb_array_elements, yangilash va qachon JSONB ishlatmaslik kerak.
Ushbu bo‘lim mundarijasi
JSONB - PostgreSQL ni boshqa relyatsion bazalardan ajratib turadigan eng mashhur imkoniyat. U bitta bazada hujjatli baza xususiyatlarini beradi.
CREATE TABLE mahsulot (
id int GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
nom text NOT NULL,
xossa jsonb NOT NULL DEFAULT '{}'
);
INSERT INTO mahsulot (nom, xossa) VALUES
('Noutbuk', '{"marka":"Lenovo","ram":16,
"ekran":{"olcham":15.6,"turi":"IPS"},
"teglar":["ish","oquv"]}'),
('Telefon', '{"marka":"Samsung","ram":8,
"ekran":{"olcham":6.5,"turi":"AMOLED"},
"teglar":["aloqa"]}'),
('Planshet', '{"marka":"Lenovo","ram":4,
"ekran":{"olcham":10.1,"turi":"IPS"},
"teglar":["oquv","oyin"]}'),
('Sichqoncha','{"marka":"Logitech","simsiz":true}');
json va jsonb #
Ikkita o'xshash tur bor va deyarli har doim ikkinchisi kerak:
json | jsonb | |
|---|---|---|
| Saqlash | Matn ko'rinishida | Ikkilik ko'rinishda |
| Yozish | Tez | Sekinroq (tahlil qilinadi) |
| O'qish | Har safar tahlil qilinadi | Tayyor |
| Indekslash | Deyarli yo'q | GIN indeks |
| Kalitlar tartibi | Saqlanadi | Saqlanmaydi |
| Takroriy kalit | Saqlanadi | Oxirgisi qoladi |
SELECT '{"b":1,"a":2,"a":3}'::json AS json_tur,
'{"b":1,"a":2,"a":3}'::jsonb AS jsonb_tur;
json_tur | jsonb_tur
---------------------+------------------
{"b":1,"a":2,"a":3} | {"a": 3, "b": 1}
(1 row)
Farq ko'rinib turibdi: json matnni o'zgarishsiz
saqladi, jsonb esa uni qayta tartibladi va takroriy kalitni
tashladi.
jsonb tanlangjson turi faqat bitta holatda kerak: kiritilgan matnni
aynan o'zgarishsiz saqlash zarur bo'lsa - masalan tashqi
tizimdan kelgan hujjatni imzosi bilan birga saqlashda.
Qolgan barcha holatlarda jsonb yaxshiroq:
- indeks qo'yish mumkin;
- operatorlar tezroq ishlaydi;
- solishtirish (
=) mantiqiy, matn darajasida emas.
Bu darslikdagi barcha misollar jsonb bilan ishlaydi.
Qiymat olish #
Hujjat ichiga kirishning to'rtta yo'li bor:
To'rtta asosiy operator bor va ularni ajratish muhim:
| Operator | Qaytaradi | Misol |
|---|---|---|
-> | JSON qiymat | xossa->'marka' |
->> | Matn | xossa->>'marka' |
#> | Yo'l bo'yicha JSON | xossa#>'{ekran,turi}' |
#>> | Yo'l bo'yicha matn | xossa#>>'{ekran,turi}' |
SELECT nom,
xossa->'marka' AS json_korinish,
xossa->>'marka' AS matn_korinish,
xossa#>>'{ekran,turi}' AS ekran_turi
FROM mahsulot
ORDER BY id;
nom | json_korinish | matn_korinish | ekran_turi
------------+---------------+---------------+------------
Noutbuk | "Lenovo" | Lenovo | IPS
Telefon | "Samsung" | Samsung | AMOLED
Planshet | "Lenovo" | Lenovo | IPS
Sichqoncha | "Logitech" | Logitech |
(4 rows)
Birinchi ustunda qo'shtirnoq bor, ikkinchisida yo'q - mana
shu -> va ->> farqi.
-> va ->> ni adashtirish - klassik xatoxossa->'marka' = 'Lenovo' yozuvi ishlamaydi.
Sabab: chap tomon jsonb turi, o'ng tomon esa matn.
PostgreSQL ularni solishtira olmaydi.
To'g'ri variantlar:
| Yozuv | Izoh |
|---|---|
xossa->>'marka' = 'Lenovo' | Matnni matn bilan - to'g'ri |
xossa->'marka' = '"Lenovo"' | JSON ni JSON bilan - ishlaydi, lekin noqulay |
Qoida: qiymat kerak bo'lsa ->>, ichiga yana kirish
kerak bo'lsa ->.
Zanjir yozganda ham shunday: xossa->'ekran'->>'turi' -
oxirgisi ->>.
Filtrlash #
SELECT nom, xossa->>'marka' AS marka, (xossa->>'ram')::int AS ram
FROM mahsulot
WHERE xossa->>'marka' = 'Lenovo'
ORDER BY id;
nom | marka | ram
----------+--------+-----
Noutbuk | Lenovo | 16
Planshet | Lenovo | 4
(2 rows)
(xossa->>'ram')::int - e'tibor bering, ->> har doim
matn qaytaradi, shuning uchun sonli taqqoslash uchun turni
o'zgartirish kerak:
SELECT nom, (xossa->>'ram')::int AS ram
FROM mahsulot
WHERE (xossa->>'ram')::int >= 8
ORDER BY ram DESC;
nom | ram
---------+-----
Noutbuk | 16
Telefon | 8
(2 rows)
Ichida bormi - @> operatori #
Bu JSONB ning eng kuchli operatori va u indekslanadi:
SELECT nom
FROM mahsulot
WHERE xossa @> '{"marka":"Lenovo"}'
ORDER BY id;
nom
----------
Noutbuk
Planshet
(2 rows)
Ichma-ich qidirish ham ishlaydi:
SELECT nom
FROM mahsulot
WHERE xossa @> '{"ekran":{"turi":"IPS"}}'
ORDER BY id;
nom
----------
Noutbuk
Planshet
(2 rows)
Kalit mavjudligini tekshirish uchun ? ishlatiladi:
SELECT nom, xossa->>'simsiz' AS simsiz
FROM mahsulot
WHERE xossa ? 'simsiz';
nom | simsiz
------------+--------
Sichqoncha | true
(1 row)
Massivlar bilan ishlash #
JSON ichidagi massivni qatorlarga yoyish:
SELECT m.nom, t.teg
FROM mahsulot m, jsonb_array_elements_text(m.xossa->'teglar') AS t(teg)
ORDER BY m.nom, t.teg;
nom | teg
----------+-------
Noutbuk | ish
Noutbuk | oquv
Planshet | oquv
Planshet | oyin
Telefon | aloqa
(5 rows)
Diqqat: Sichqoncha chiqmadi - unda teglar kaliti yo'q.
Uni ham qo'shish uchun LEFT JOIN LATERAL kerak bo'ladi.
O'zgartirish #
JSONB ni yangilash uchun maxsus funksiyalar bor:
SELECT (xossa || '{"kafolat":24}')->>'kafolat' AS qoshildi,
(xossa - 'teglar') ? 'teglar' AS teglar_qoldimi,
jsonb_set(xossa, '{ram}', '32')->>'ram' AS yangi_ram
FROM mahsulot
WHERE nom = 'Noutbuk';
qoshildi | teglar_qoldimi | yangi_ram
----------+----------------+-----------
24 | f | 32
(1 row)
| Amal | Operator |
|---|---|
| Qo'shish yoki almashtirish | || |
| Kalitni o'chirish | - |
| Chuqurdagi qiymatni o'zgartirish | jsonb_set |
Kalitlarni ko'rish #
SELECT nom, jsonb_object_keys(xossa) AS kalit
FROM mahsulot
WHERE nom = 'Sichqoncha';
nom | kalit
------------+--------
Sichqoncha | marka
Sichqoncha | simsiz
(2 rows)
JSONB qulay, shuning uchun uni haddan tashqari ishlatish oson. Bu klassik xato.
| JSONB to'g'ri | JSONB noto'g'ri |
|---|---|
| Har mahsulotda har xil xossalar | Har mahsulotda bor narx |
| Tashqi API javobini saqlash | Foydalanuvchi email i |
| Sozlamalar, moslamalar | Buyurtma summasi |
| Kamdan-kam so'raladigan tafsilot | Doim filtrlanadigan maydon |
Sabab uchta:
- JSONB ichidagi maydonga tashqi kalit qo'yib bo'lmaydi.
NOT NULLvaCHECKcheklovlari ancha noqulay yoziladi.- Har o'qishda tur o'zgartirish kerak - xato ehtimoli oshadi.
Amaliy qoida: bilinadigan va doimiy maydonlar ustun bo'lsin, o'zgaruvchan va noaniq qismi JSONB da.
jsonvajsonbga bir xil matn bering va farqni ko'ring.- Takroriy kalit qaysi turda saqlanib qolganini yozing.
->va->>natijalarini solishtiring.xossa->'marka' = 'Lenovo'yozib ko'ring - nima bo'ldi?- Xatoni to'g'rilang va tushuntiring.
#>>bilan ichma-ich qiymatni oling.@>bilan ma'lum markani filtrlang.?bilan ma'lum kalit bor mahsulotlarni toping.jsonb_array_elements_textbilan teglarni yoying.- Qaysi maydonlar ustun, qaysilari JSONB bo'lishi kerakligini yozing.
Xulosa #
jsonbikkilik ko'rinishda saqlanadi, indekslanadi va tezroq o'qiladi.jsonfaqat matnni aynan saqlash kerak bo'lganda ishlatiladi.jsonbkalitlar tartibini saqlamaydi va takroriy kalitdan oxirgisini qoldiradi.->JSON,->>esa matn qaytaradi - eng ko'p adashtiriladigan joy.- Taqqoslashda deyarli har doim
->>kerak. ->>matn qaytargani uchun sonli shartda turni o'zgartiring:(x->>'ram')::int.@>ichida bormi degan savolga javob beradi va indekslanadi.?kalit mavjudligini tekshiradi.jsonb_array_elements_textJSON massivini qatorlarga yoyadi.- Doimiy va filtrlanadigan maydonlarni ustun qiling, JSONB ni o'zgaruvchan qism uchun qoldiring.
Keyingi bo'limda matn ichidan qidirishni - to'liq matn qidiruv ni ko'ramiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.