12-bo‘lim

JSONB

json va jsonb farqi, qiymat olish operatorlari, ichma-ich yo'l, jsonb_array_elements, yangilash va qachon JSONB ishlatmaslik kerak.

🕑 13 daqiqa o‘qish 📄 724 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. json va jsonb
  2. Qiymat olish
  3. Filtrlash
  4. Ichida bormi - @> operatori
  5. Massivlar bilan ishlash
  6. O'zgartirish
  7. Kalitlarni ko'rish
  8. Xulosa

JSONB - PostgreSQL ni boshqa relyatsion bazalardan ajratib turadigan eng mashhur imkoniyat. U bitta bazada hujjatli baza xususiyatlarini beradi.

SQL
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:

jsonjsonb
SaqlashMatn ko'rinishidaIkkilik ko'rinishda
YozishTezSekinroq (tahlil qilinadi)
O'qishHar safar tahlil qilinadiTayyor
IndekslashDeyarli yo'qGIN indeks
Kalitlar tartibiSaqlanadiSaqlanmaydi
Takroriy kalitSaqlanadiOxirgisi qoladi
SQL
SELECT '{"b":1,"a":2,"a":3}'::json  AS json_tur,
       '{"b":1,"a":2,"a":3}'::jsonb AS jsonb_tur;
Natija
      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.

Deyarli har doim jsonb tanlang

json 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:

Hujjat daraxti va unga murojaat { "marka" : "Lenovo", "ram" : 16, "ekran" : { "olcham" : 15.6, "turi" : "IPS" } } xossa->'marka' natija: "Lenovo" - JSON, qo'shtirnoq bilan xossa->>'marka' natija: Lenovo - oddiy matn xossa#>'{ekran,turi}' ichma-ich yo'l bo'yicha JSON xossa#>>'{ekran,turi}' ichma-ich yo'l bo'yicha matn Bitta qoida yetarli Qiymat kerak bo'lsa - ikkita belgi; ichiga yana kirish kerak bo'lsa - bitta
Zanjirning oxirgi bo'g'ini deyarli har doim ->> bo'ladi

To'rtta asosiy operator bor va ularni ajratish muhim:

OperatorQaytaradiMisol
->JSON qiymatxossa->'marka'
->>Matnxossa->>'marka'
#>Yo'l bo'yicha JSONxossa#>'{ekran,turi}'
#>>Yo'l bo'yicha matnxossa#>>'{ekran,turi}'
SQL
SELECT nom,
       xossa->'marka'   AS json_korinish,
       xossa->>'marka'  AS matn_korinish,
       xossa#>>'{ekran,turi}' AS ekran_turi
FROM mahsulot
ORDER BY id;
Natija
    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 xato

xossa->'marka' = 'Lenovo' yozuvi ishlamaydi.

Sabab: chap tomon jsonb turi, o'ng tomon esa matn. PostgreSQL ularni solishtira olmaydi.

To'g'ri variantlar:

YozuvIzoh
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 #

SQL
SELECT nom, xossa->>'marka' AS marka, (xossa->>'ram')::int AS ram
FROM mahsulot
WHERE xossa->>'marka' = 'Lenovo'
ORDER BY id;
Natija
   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:

SQL
SELECT nom, (xossa->>'ram')::int AS ram
FROM mahsulot
WHERE (xossa->>'ram')::int >= 8
ORDER BY ram DESC;
Natija
   nom   | ram
---------+-----
 Noutbuk |  16
 Telefon |   8
(2 rows)

Ichida bormi - @> operatori #

Bu JSONB ning eng kuchli operatori va u indekslanadi:

SQL
SELECT nom
FROM mahsulot
WHERE xossa @> '{"marka":"Lenovo"}'
ORDER BY id;
Natija
   nom
----------
 Noutbuk
 Planshet
(2 rows)

Ichma-ich qidirish ham ishlaydi:

SQL
SELECT nom
FROM mahsulot
WHERE xossa @> '{"ekran":{"turi":"IPS"}}'
ORDER BY id;
Natija
   nom
----------
 Noutbuk
 Planshet
(2 rows)

Kalit mavjudligini tekshirish uchun ? ishlatiladi:

SQL
SELECT nom, xossa->>'simsiz' AS simsiz
FROM mahsulot
WHERE xossa ? 'simsiz';
Natija
    nom     | simsiz
------------+--------
 Sichqoncha | true
(1 row)

Massivlar bilan ishlash #

JSON ichidagi massivni qatorlarga yoyish:

SQL
SELECT m.nom, t.teg
FROM mahsulot m, jsonb_array_elements_text(m.xossa->'teglar') AS t(teg)
ORDER BY m.nom, t.teg;
Natija
   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:

SQL
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';
Natija
 qoshildi | teglar_qoldimi | yangi_ram
----------+----------------+-----------
 24       | f              | 32
(1 row)
AmalOperator
Qo'shish yoki almashtirish||
Kalitni o'chirish-
Chuqurdagi qiymatni o'zgartirishjsonb_set

Kalitlarni ko'rish #

SQL
SELECT nom, jsonb_object_keys(xossa) AS kalit
FROM mahsulot
WHERE nom = 'Sichqoncha';
Natija
    nom     | kalit
------------+--------
 Sichqoncha | marka
 Sichqoncha | simsiz
(2 rows)
JSONB - sxemaning o'rnini bosmaydi

JSONB qulay, shuning uchun uni haddan tashqari ishlatish oson. Bu klassik xato.

JSONB to'g'riJSONB noto'g'ri
Har mahsulotda har xil xossalarHar mahsulotda bor narx
Tashqi API javobini saqlashFoydalanuvchi email i
Sozlamalar, moslamalarBuyurtma summasi
Kamdan-kam so'raladigan tafsilotDoim filtrlanadigan maydon

Sabab uchta:

  1. JSONB ichidagi maydonga tashqi kalit qo'yib bo'lmaydi.
  2. NOT NULL va CHECK cheklovlari ancha noqulay yoziladi.
  3. 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.

Amaliy topshiriq
  1. json va jsonb ga bir xil matn bering va farqni ko'ring.
  2. Takroriy kalit qaysi turda saqlanib qolganini yozing.
  3. -> va ->> natijalarini solishtiring.
  4. xossa->'marka' = 'Lenovo' yozib ko'ring - nima bo'ldi?
  5. Xatoni to'g'rilang va tushuntiring.
  6. #>> bilan ichma-ich qiymatni oling.
  7. @> bilan ma'lum markani filtrlang.
  8. ? bilan ma'lum kalit bor mahsulotlarni toping.
  9. jsonb_array_elements_text bilan teglarni yoying.
  10. Qaysi maydonlar ustun, qaysilari JSONB bo'lishi kerakligini yozing.

Xulosa #

  • jsonb ikkilik ko'rinishda saqlanadi, indekslanadi va tezroq o'qiladi.
  • json faqat matnni aynan saqlash kerak bo'lganda ishlatiladi.
  • jsonb kalitlar 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_text JSON 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.

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.