PostgreSQL'de JSON verisini jsonb tipinde bir sütunda saklar, alanlara -> (JSON olarak) ve ->> (metin olarak) operatörleriyle erişir, belge içinde arama için @> (içerir) ve ? (anahtar var mı) operatörlerini kullanırsınız. Bu aramaları hızlandırmak için sütuna bir GIN indeksi eklenir. Değer güncellemek için jsonb_set, || birleştirme operatörü ya da köşeli parantezli atama kullanılır.

Bu yazı json ile jsonb arasındaki farkı, temel operatörleri, JSON null ile SQL NULL ayrımını, güncelleme yollarını, satırlardan JSON üretmeyi, JSON'u satırlara açmayı ve indekslemeyi çalıştırılmış örneklerle anlatır. jsonpath dili, JSON_VALUE, JSON_QUERY ve JSON_TABLE gibi SQL/JSON fonksiyonları ise kardeş yazı SQL/JSON, jsonpath ve JSON_TABLE içinde. Örnekler PostgreSQL 18.1 üzerinde çalıştırıldı; serinin geri kalanı için PostgreSQL öğrenme rehberi.

json ile jsonb arasındaki fark

json ile jsonb arasındaki fark: Saklama, Boşluk ve anahtar sırası, Tekrarlanan anahtar, @> ve ? operatörleri

İki tip de girdinin geçerli JSON olmasını zorunlu kılar, ama saklama biçimleri farklıdır. json girilen metnin birebir kopyasını tutar ve her işlemde yeniden ayrıştırır. jsonb ise ayrıştırılmış ikili bir biçimde saklanır: yazarken biraz daha yavaştır, okurken ve işlerken çok daha hızlıdır ve indekslenebilir. Bu yüzden belgeler, anahtar sırasına bağımlı eski bir sistem gibi özel bir gerekçe yoksa çoğu uygulamada jsonb kullanılmasını önerir.

Fark aynı metni iki tipe çevirince görülür. json boşlukları, anahtar sırasını ve tekrarlanan anahtarları olduğu gibi korur. jsonb boşlukları atar, anahtarları kendi iç sırasına dizer ve tekrarlanan anahtarlardan yalnızca sonuncusunu tutar:

sql
SELECT '{"ad": "Kalem", "fiyat": 12.50, "ad": "Defter",  "stok":3}'::json  AS json_tipi;
SELECT '{"ad": "Kalem", "fiyat": 12.50, "ad": "Defter",  "stok":3}'::jsonb AS jsonb_tipi;
text
                         json_tipi                          
------------------------------------------------------------
 {"ad": "Kalem", "fiyat": 12.50, "ad": "Defter",  "stok":3}
(1 row)

                 jsonb_tipi                  
---------------------------------------------
 {"ad": "Defter", "stok": 3, "fiyat": 12.50}
(1 row)
Özellikjsonjsonb
Saklamagirilen metnin kopyasıayrıştırılmış ikili biçim
Boşluk ve anahtar sırasıkorunurkorunmaz
Tekrarlanan anahtarhepsi tutuluryalnızca sonuncusu
@> ve ? operatörleriyokvar
GIN indeksyokvar
Eşitlik ve sıralama operatörleriyokvar

JSON sayıları jsonb içinde PostgreSQL'in numeric tipine eşlenir; bu yüzden 12.50 sondaki sıfırıyla korunur, numeric aralığı dışındaki sayılar ise reddedilir. JSON metinleri text tipine eşlenir ve \u0000 kabul edilmez. Mantıksal değerlerde yalnızca küçük harfli true ve false geçerlidir.

Örnek tablo

Ürünlerin değişken özelliklerini bir jsonb sütununda tutan küçük bir tablo kuralım. Belgelerin tasarım önerisi de dikkate değer: JSON esnek olsa bile belgelerin öngörülebilir bir yapıda olması sorgu yazmayı kolaylaştırır. Ayrıca bir JSON değerini güncellemek bütün satırı kilitler; çok büyük ve sık güncellenen belgeler eşzamanlı işlemlerde kilit çekişmesine yol açabilir.

sql
CREATE TABLE urun (
    id      int PRIMARY KEY,
    ad      text NOT NULL,
    ozellik jsonb NOT NULL DEFAULT '{}'
);
INSERT INTO urun VALUES
  (1, 'Dizüstü Bilgisayar', '{"marka": "Ankara Tekno", "ram_gb": 16, "renk": ["gri", "siyah"], "garanti": {"yil": 2, "tip": "üretici"}}'),
  (2, 'Kablosuz Fare',      '{"marka": "İzmir Elektronik", "renk": ["beyaz"], "pil": true}'),
  (3, 'Monitör',            '{"marka": "Ankara Tekno", "boyut_inc": 27, "garanti": {"yil": 3, "tip": "satıcı"}, "indirim": null}');

Alanlara erişim: ->, ->>, #> ve #>>

-> bir anahtarın değerini jsonb olarak, ->> ise text olarak döndürür. Çıktıdaki tırnaklar farkı açıkça gösterir:

sql
SELECT id, ozellik -> 'marka' AS ok, ozellik ->> 'marka' AS cift_ok,
       pg_typeof(ozellik -> 'marka') AS tip1, pg_typeof(ozellik ->> 'marka') AS tip2
FROM urun ORDER BY id;
text
 id |         ok         |     cift_ok      | tip1  | tip2 
----+--------------------+------------------+-------+------
  1 | "Ankara Tekno"     | Ankara Tekno     | jsonb | text
  2 | "İzmir Elektronik" | İzmir Elektronik | jsonb | text
  3 | "Ankara Tekno"     | Ankara Tekno     | jsonb | text
(3 rows)

İç içe değerlere operatörleri zincirleyerek ya da #> ve #>> ile bir yol dizisi vererek ulaşırsınız. Dizi elemanları sıfırdan başlar ve negatif sayılar sondan sayar. PostgreSQL ayrıca köşeli parantezli erişimi destekler; bu yazımın sonucu her zaman jsonb olur:

sql
SELECT id, ozellik -> 'garanti' ->> 'yil' AS garanti_yil,
       ozellik #>> '{garanti,tip}' AS garanti_tip,
       ozellik -> 'renk' ->> 0 AS ilk_renk,
       ozellik['renk'][0] AS subscript
FROM urun ORDER BY id;
text
 id | garanti_yil | garanti_tip | ilk_renk | subscript 
----+-------------+-------------+----------+-----------
  1 | 2           | üretici     | gri      | "gri"
  2 |             |             | beyaz    | "beyaz"
  3 | 3           | satıcı      |          | 
(3 rows)

Olmayan bir anahtar ya da uyumsuz bir yapı hata vermez, NULL döndürür. Bu davranış farklı yapıdaki belgeleri sorgularken işe yarar, ama yazım hatası yaptığınız bir anahtar adı da sessizce NULL üretir.

Karşılaştırmadan önce tipe çevirin

->> metin döndürdüğü için sayısal karşılaştırmada önce tip dönüşümü gerekir. Dönüşümü unutmak sessiz ve yanlış sonuç verir; metin karşılaştırmasında "16" ile "8" ilk karaktere göre kıyaslanır:

sql
SELECT id, ad FROM urun WHERE (ozellik ->> 'ram_gb')::int >= 16;
SELECT id, ad FROM urun WHERE ozellik ->> 'ram_gb' >= '8';
text
 id |         ad         
----+--------------------
  1 | Dizüstü Bilgisayar
(1 row)

 id | ad 
----+----
(0 rows)

Değerin tipini bilmiyorsanız jsonb_typeof() size object, array, string, number, boolean ya da null değerlerinden birini söyler. Anahtar hiç yoksa sonuç SQL NULL olur.

İçerme (@>) ve varlık (?) operatörleri

İçerme (@>) ve varlık (?) operatörleri

@> soldaki belgenin sağdaki belgeyi içerip içermediğini sınar. İçerme iç içe çalışır: sağdaki yapının soldakiyle yapı ve veri olarak eşleşmesi gerekir, soldaki fazladan anahtarlar ve dizi elemanları önemsenmez. Dizilerde eleman sırası ve tekrar önemli değildir:

sql
SELECT id, ad FROM urun WHERE ozellik @> '{"marka": "Ankara Tekno"}' ORDER BY id;
SELECT id, ad FROM urun WHERE ozellik @> '{"renk": ["siyah"]}' ORDER BY id;
text
 id |         ad         
----+--------------------
  1 | Dizüstü Bilgisayar
  3 | Monitör
(2 rows)

 id |         ad         
----+--------------------
  1 | Dizüstü Bilgisayar
(1 row)

? operatörü bir metnin en üst seviyede anahtar ya da dizi elemanı olarak bulunup bulunmadığını sınar; değerlere bakmaz ve iç içe aramaz. ?| verilen dizideki anahtarlardan herhangi biri, ?& hepsi için doğru döner:

sql
SELECT id, ad, ozellik ? 'pil' AS pil_var, ozellik ? 'gri' AS gri_anahtar_mi,
       ozellik -> 'renk' ? 'gri' AS renkte_gri
FROM urun ORDER BY id;

SELECT id, ozellik ?| array['pil', 'boyut_inc'] AS herhangi, ozellik ?& array['marka', 'garanti'] AS hepsi
FROM urun ORDER BY id;
text
 id |         ad         | pil_var | gri_anahtar_mi | renkte_gri 
----+--------------------+---------+----------------+------------
  1 | Dizüstü Bilgisayar | f       | f              | t
  2 | Kablosuz Fare      | t       | f              | f
  3 | Monitör            | f       | f              | 
(3 rows)

 id | herhangi | hepsi 
----+----------+-------
  1 | f        | t
  2 | t        | f
  3 | t        | t
(3 rows)

"gri" belgenin en üst seviyesinde olmadığı için ikinci sütun hep yanlış; renk dizisine inince bulunuyor. 3 numaralı üründe renk anahtarı olmadığı için ozellik -> 'renk' NULL döndü ve karşılaştırma da NULL oldu. Belgeler, çok sayıda anahtar ya da eleman içeren aramalarda nesnelerin dizilerden daha uygun olduğunu belirtir, çünkü nesneler arama için içeride düzenlenmiştir, diziler ise doğrusal taranır.

JSON null ile SQL NULL aynı şey değil

JSON içindeki null bir değerdir; SQL'deki NULL ise değerin yokluğudur. 3 numaralı üründeki "indirim": null alanını inceleyelim:

sql
SELECT id, ozellik -> 'indirim' AS json_null, ozellik ->> 'indirim' AS metin,
       (ozellik ->> 'indirim') IS NULL AS sql_null_mu,
       ozellik ? 'indirim' AS anahtar_var, ozellik -> 'yok' AS olmayan
FROM urun WHERE id = 3;
text
 id | json_null | metin | sql_null_mu | anahtar_var | olmayan 
----+-----------+-------+-------------+-------------+---------
  3 | null      |       | t           | t           | 
(1 row)

-> JSON null değerini döndürdü, ->> ise bunu SQL NULL'a çevirdi. Olmayan bir anahtar da SQL NULL verdi. Anahtarın hiç olmamasıyla değerinin null olmasını ayırt etmek istiyorsanız ? operatörünü kullanın. PostgreSQL 18 sürüm notları bu alanda bir değişiklik yaptı: jsonb null değerleri artık skaler tiplere NULL olarak dönüştürülebiliyor, önceki sürümlerde bu dönüşüm hata veriyordu. Bu kümede ('null'::jsonb)::int hata vermeden NULL döndürdü.

Güncelleme: jsonb_set, ||, - ve köşeli parantez

JSON belgesinin bir parçasını değiştirmek için beş yaygın yol vardır: bir yoldaki değeri jsonb_set ile değiştirmek, || ile üst seviye anahtarları birleştirmek, - ile anahtar silmek, #- ile bir yoldaki öğeyi silmek ve UPDATE ... SET sutun['anahtar'] = ... biçiminde köşeli parantezle atamak. Aşağıdaki komutların hepsi aynı tabloda çalıştırıldı:

sql
UPDATE urun SET ozellik = jsonb_set(ozellik, '{ram_gb}', '32') WHERE id = 1;
UPDATE urun SET ozellik = jsonb_set(ozellik, '{garanti,yil}', '4') WHERE id = 1;
UPDATE urun SET ozellik = ozellik || '{"stok": 15, "renk": ["mavi"]}' WHERE id = 2;
UPDATE urun SET ozellik = ozellik - 'indirim' WHERE id = 3;
UPDATE urun SET ozellik['garanti']['tip'] = '"uzatılmış"' WHERE id = 3;
SELECT id, ozellik FROM urun ORDER BY id;
text
 id |                                                  ozellik                                                   
----+------------------------------------------------------------------------------------------------------------
  1 | {"renk": ["gri", "siyah"], "marka": "Ankara Tekno", "ram_gb": 32, "garanti": {"tip": "üretici", "yil": 4}}
  2 | {"pil": true, "renk": ["mavi"], "stok": 15, "marka": "İzmir Elektronik"}
  3 | {"marka": "Ankara Tekno", "garanti": {"tip": "uzatılmış", "yil": 3}, "boyut_inc": 27}
(3 rows)

2 numaralı üründe dikkat edilmesi gereken bir nokta var: || yalnızca üst seviyede birleştirir ve aynı anahtar varsa sağdakinin değerini alır. Bu yüzden renk dizisine "mavi" eklenmedi, dizi tamamen "mavi" ile değişti. Diziye eleman eklemek için jsonb_insert ya da dizinin kendisini birleştiren bir ifade kullanmanız gerekir. Köşeli parantezli atamada atanan değerin de jsonb olması gerektiği için metin değeri çift tırnak içinde yazıldı.

jsonb_set tuzakları

jsonb_set(hedef, yol, yeni_deger, create_if_missing) son yol adımı yoksa onu ekler (dördüncü argüman varsayılan olarak doğrudur), ama yoldaki önceki adımların hepsinin var olması gerekir; yoksa belge değişmeden döner. En tehlikeli durum ise yeni değerin SQL NULL olmasıdır: fonksiyon bu durumda bütün sonucu NULL yapar. NOT NULL kısıtı olmayan bir sütunda bu, bir UPDATE ile bütün belgenin silinmesi demektir. jsonb_set_lax NULL için ne yapılacağını seçmenizi sağlar (use_json_null varsayılan, delete_key, return_target, raise_exception):

sql
SELECT jsonb_set('{"a": 1}', '{x,y}', '2') AS ara_yol_yok,
       jsonb_set('{"a": 1}', '{b}', '2', false) AS create_false,
       jsonb_set('{"a": 1}', '{a}', NULL) AS null_deger,
       jsonb_set_lax('{"a": 1}', '{a}', NULL) AS lax_ile,
       jsonb_set_lax('{"a": 1}', '{a}', NULL, true, 'delete_key') AS lax_sil;
text
 ara_yol_yok | create_false | null_deger |   lax_ile   | lax_sil 
-------------+--------------+------------+-------------+---------
 {"a": 1}    | {"a": 1}     |            | {"a": null} | {}
(1 row)

Dizilere ekleme ve silme için jsonb_insert verilen konumun önüne (dördüncü argüman doğruysa arkasına) ekler, #- bir yoldaki öğeyi siler, dizi üzerinde - metin ise o metne eşit bütün elemanları kaldırır:

sql
SELECT jsonb_insert('{"renk": ["gri", "siyah"]}', '{renk,1}', '"kırmızı"') AS araya,
       '{"renk": ["gri", "siyah"]}'::jsonb #- '{renk,0}' AS yol_sil,
       '["a","b","a"]'::jsonb - 'a' AS dizi_eleman_sil;
text
                 araya                 |       yol_sil       | dizi_eleman_sil 
---------------------------------------+---------------------+-----------------
 {"renk": ["gri", "kırmızı", "siyah"]} | {"renk": ["siyah"]} | ["b"]
(1 row)

Satırlardan JSON üretmek

API yanıtı hazırlarken satırları JSON'a çevirmek sık yapılan bir iştir. jsonb_build_object sırayla anahtar ve değer alarak nesne kurar, jsonb_agg birden çok satırı tek bir dizide toplar ve içinde ORDER BY kabul eder. to_jsonb(satir) bütün satırı nesneye çevirir; istemediğiniz alanları - ile atabilirsiniz:

sql
SELECT jsonb_build_object('id', id, 'ad', ad, 'marka', ozellik ->> 'marka') AS nesne
FROM urun ORDER BY id;

SELECT jsonb_agg(jsonb_build_object('id', id, 'ad', ad) ORDER BY id) AS liste FROM urun;

SELECT to_jsonb(u) - 'ozellik' AS satir FROM urun u WHERE id = 2;
text
                             nesne                              
----------------------------------------------------------------
 {"ad": "Dizüstü Bilgisayar", "id": 1, "marka": "Ankara Tekno"}
 {"ad": "Kablosuz Fare", "id": 2, "marka": "İzmir Elektronik"}
 {"ad": "Monitör", "id": 3, "marka": "Ankara Tekno"}
(3 rows)

                                                 liste                                                 
-------------------------------------------------------------------------------------------------------
 [{"ad": "Dizüstü Bilgisayar", "id": 1}, {"ad": "Kablosuz Fare", "id": 2}, {"ad": "Monitör", "id": 3}]
(1 row)

              satir               
----------------------------------
 {"ad": "Kablosuz Fare", "id": 2}
(1 row)

JSON'u satırlara açmak

Ters yönde, bir JSON dizisini satırlara açmak için jsonb_array_elements (ya da metin döndüren _text sürümü), nesnenin anahtar ve değerlerini satır yapmak için jsonb_each, yalnızca anahtarları listelemek için jsonb_object_keys kullanılır. Bunlar küme döndüren fonksiyonlardır ve FROM içinde tabloyla yan yana yazılabilir:

sql
SELECT u.id, r.renk FROM urun u, jsonb_array_elements_text(u.ozellik -> 'renk') AS r(renk) ORDER BY u.id, r.renk;

SELECT key, value, jsonb_typeof(value) FROM urun, jsonb_each(ozellik) WHERE id = 1 ORDER BY key;
text
 id | renk  
----+-------
  1 | gri
  1 | siyah
  2 | mavi
(3 rows)

   key   |            value             | jsonb_typeof 
---------+------------------------------+--------------
 garanti | {"tip": "üretici", "yil": 4} | object
 marka   | "Ankara Tekno"               | string
 ram_gb  | 32                           | number
 renk    | ["gri", "siyah"]             | array
(4 rows)

İlk sorguda renk anahtarı olmayan 3 numaralı ürün sonuçtan düştü. Bu tür birleşmenin satır elemesini ve LEFT JOIN LATERAL ile nasıl korunacağını JOIN türleri ve LATERAL yazısında bulabilirsiniz. Bilinen yapıdaki bir belgeyi doğrudan tipli sütunlara çevirmek için jsonb_to_record kullanılır:

sql
SELECT * FROM jsonb_to_record('{"ad": "Klavye", "fiyat": 450.90, "stokta": true}') AS t(ad text, fiyat numeric, stokta boolean);
text
   ad   | fiyat  | stokta 
--------+--------+--------
 Klavye | 450.90 | t
(1 row)

Okunabilir çıktı için jsonb_pretty, NULL alanları atmak için jsonb_strip_nulls vardır. PostgreSQL 18 ile jsonb_strip_nulls fonksiyonuna dizilerdeki null elemanları da kaldırmayı sağlayan isteğe bağlı ikinci bir parametre eklendi:

sql
SELECT jsonb_strip_nulls('{"a": 1, "b": null, "c": [1, null]}') AS varsayilan,
       jsonb_strip_nulls('{"a": 1, "b": null, "c": [1, null]}', true) AS dizide_de;
text
        varsayilan        |     dizide_de      
--------------------------+--------------------
 {"a": 1, "c": [1, null]} | {"a": 1, "c": [1]}
(1 row)

GIN indeks ile JSONB aramalarını hızlandırmak

jsonb sütunlarında arama için GIN indeksi kullanılır ve iki operatör sınıfı vardır. Varsayılan jsonb_ops ?, ?|, ?&, @> ile jsonpath operatörleri @? ve @@ için çalışır. jsonb_path_ops anahtar varlık operatörlerini desteklemez, yalnızca @>, @? ve @@ için çalışır; karşılığında genellikle daha küçüktür ve aramaları daha seçicidir. Belgelerin açıklamasına göre jsonb_ops her anahtar ve değer için ayrı indeks öğesi üretir, jsonb_path_ops ise yalnızca değerler için, değere giden anahtarlarla birlikte bir özet değeri olarak öğe üretir.

Planı görmek için tabloya 20.000 sentetik satır ekleyip iki indeksi de oluşturduk (örnek amaçlı; gerçekte ikisinden birini seçersiniz):

sql
INSERT INTO urun SELECT g, 'Ürün ' || g, jsonb_build_object('marka', CASE WHEN g % 10 = 0 THEN 'Bursa Ofis' ELSE 'Diğer' END, 'kod', g)
FROM generate_series(4, 20000) AS g;
CREATE INDEX urun_ozellik_gin ON urun USING GIN (ozellik);
CREATE INDEX urun_ozellik_path ON urun USING GIN (ozellik jsonb_path_ops);
ANALYZE urun;

EXPLAIN (COSTS OFF) SELECT id FROM urun WHERE ozellik @> '{"marka": "Ankara Tekno"}';
EXPLAIN (COSTS OFF) SELECT id FROM urun WHERE ozellik ? 'pil';
EXPLAIN (COSTS OFF) SELECT id FROM urun WHERE ozellik ->> 'marka' = 'Ankara Tekno';
text
                             QUERY PLAN                              
---------------------------------------------------------------------
 Bitmap Heap Scan on urun
   Recheck Cond: (ozellik @> '{"marka": "Ankara Tekno"}'::jsonb)
   ->  Bitmap Index Scan on urun_ozellik_path
         Index Cond: (ozellik @> '{"marka": "Ankara Tekno"}'::jsonb)
(4 rows)

                 QUERY PLAN                  
---------------------------------------------
 Bitmap Heap Scan on urun
   Recheck Cond: (ozellik ? 'pil'::text)
   ->  Bitmap Index Scan on urun_ozellik_gin
         Index Cond: (ozellik ? 'pil'::text)
(4 rows)

                           QUERY PLAN                           
----------------------------------------------------------------
 Seq Scan on urun
   Filter: ((ozellik ->> 'marka'::text) = 'Ankara Tekno'::text)
(2 rows)

Planlayıcı @> sorgusunda jsonb_path_ops indeksini, ? sorgusunda ise bunu destekleyen tek indeks olan jsonb_ops indeksini seçti. Üçüncü sorgu önemli bir dersi gösteriyor: ozellik ->> 'marka' = ... biçimindeki bir eşitlik GIN indeksini kullanamaz, çünkü GIN bu operatörü desteklemez. Ya sorguyu @> ile yazın ya da o ifade üzerinde ayrı bir B-tree ifade indeksi oluşturun:

sql
CREATE INDEX urun_marka_idx ON urun ((ozellik ->> 'marka'));
ANALYZE urun;
EXPLAIN (COSTS OFF) SELECT id FROM urun WHERE ozellik ->> 'marka' = 'Ankara Tekno';
text
                             QUERY PLAN                             
--------------------------------------------------------------------
 Index Scan using urun_marka_idx on urun
   Index Cond: ((ozellik ->> 'marka'::text) = 'Ankara Tekno'::text)
(2 rows)

Belgeler aynı fikri tags gibi tek bir alt anahtar için de önerir: CREATE INDEX ... USING GIN ((sutun -> 'tags')) biçimindeki hedefli bir ifade indeksi, bütün belgeyi kapsayan indeksten genellikle daha küçük ve hızlıdır, ama yalnızca o ifadeyle yazılmış sorgularda kullanılır. İndeks türlerinin genel karşılaştırması PostgreSQL indeks türleri, plan okumanın ayrıntısı EXPLAIN ANALYZE ile plan okuma yazısında.

Geçersiz JSON girdisi

JSON tipleri girdiyi doğrular. Sonda fazladan virgül gibi bir yazım hatası satırın eklenmesini engeller ve hata mesajı sorunun yerini gösterir:

sql
SELECT '{"ad": "Kalem", }'::jsonb;
text
ERROR:  invalid input syntax for type json
LINE 1: SELECT '{"ad": "Kalem", }'::jsonb;
               ^
DETAIL:  Expected string, but found "}".
CONTEXT:  JSON data, line 1: {"ad": "Kalem", }

Bir metnin geçerli JSON olup olmadığını hata almadan sınamak için IS JSON yüklemini kullanabilirsiniz; bu da SQL/JSON yazısında anlatılıyor.

Sık yapılan hatalar

Sık yapılan hatalar: -> ile ->> farkını karıştırmak, ->> sonucunu tip dönüşümü olmadan sayı gibi karşılaştırmak., jsonb_set fonksiyonuna NULL değer vermek ve bütün belgeyi...
  • -> ile ->> farkını karıştırmak: ozellik -> 'marka' = 'Ankara Tekno' metinle değil JSON değeriyle karşılaştırma yapar.
  • ->> sonucunu tip dönüşümü olmadan sayı gibi karşılaştırmak.
  • jsonb_set fonksiyonuna NULL değer vermek ve bütün belgeyi kaybetmek.
  • || operatörünün iç içe birleştirme yaptığını sanmak; yalnızca üst seviyede birleştirir.
  • ? operatörünün iç içe arama yaptığını düşünmek; yalnızca en üst seviyeye bakar.
  • GIN indeksi olduğu için ->> eşitliğinin de hızlanacağını beklemek.
  • Her alanı JSON'a koymak: sık sorgulanan, kısıt ve yabancı anahtar gerektiren alanlar normal sütunlarda daha iyi durur. Kısıtlar için PRIMARY KEY, FOREIGN KEY ve kısıtlar.

Sık Sorulan Sorular

json mu jsonb mi kullanmalıyım?

Çoğu durumda jsonb. json yalnızca belgeyi birebir (boşluk ve anahtar sırasıyla) saklamanız gerekiyorsa anlamlıdır. @>, ? operatörleri, GIN indeksi ve eşitlik karşılaştırması yalnızca jsonb için vardır.

JSONB içindeki bir alanı nasıl güncellerim?

UPDATE tablo SET sutun = jsonb_set(sutun, '{anahtar}', '"yeni"') ya da UPDATE tablo SET sutun['anahtar'] = '"yeni"'. İki yazımda da yeni değer jsonb olmalıdır; metin için çift tırnak gerekir.

JSONB sorgularım neden indeks kullanmıyor?

İndeksin operatör sınıfının sorgudaki operatörü desteklemesi gerekir. GIN yalnızca @>, ? ailesi ve jsonpath operatörleri için çalışır; ->> ile eşitlik için ifade indeksi gerekir. Ayrıca çok küçük tablolarda planlayıcı sıralı taramayı tercih edebilir.

Bir JSON dizisinin eleman sayısını nasıl bulurum?

jsonb_array_length(sutun -> 'renk') dizinin üst seviye eleman sayısını verir; değer dizi değilse hata verir.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: PostgreSQL öğrenme rehberi · SQL/JSON ve JSON_TABLE · array (dizi) tipi · indeks türleri · EXPLAIN ile plan okuma · veri tipleri · CSV ve JSON dönüşümü