JSONB — один из ключевых типов данных PostgreSQL. В отличие от JSON (текст), JSONB хранится в бинарном формате, поддерживает индексы и мощные операторы. Разберём весь арсенал.
JSONB vs JSON
| JSON | JSONB |
|---|
| Хранение | Текст (as-is) | Бинарный (оптимизирован) |
| Запись | Быстрее | Чуть медленнее |
| Чтение | Медленнее | Быстрее |
| Индексы | Только cast | GIN, GiST |
| Порядок ключей | Сохраняется | Нет |
| Дубликаты ключей | Сохраняются | Последний выигрывает |
| Рекомендация | Почти никогда | ✅ Всегда |
Создание и вставка
CREATE TABLE products (
id SERIAL PRIMARY KEY,
data JSONB NOT NULL
);
INSERT INTO products (data) VALUES
('{
"name": "Ноутбук",
"price": 85000,
"specs": {
"ram": 16,
"storage": 512,
"display": "15.6"
},
"tags": ["electronics", "laptop"],
"in_stock": true
}');
Операторы извлечения
SELECT data -> 'name' FROM products;
SELECT data -> 'specs' -> 'ram' FROM products;
SELECT data ->> 'name' FROM products;
SELECT data #> '{specs, ram}' FROM products;
SELECT data #>> '{specs, ram}' FROM products;
SELECT data -> 'tags' -> 0 FROM products;
SELECT data ->> 'tags' ->> 1 FROM products;
Операторы проверки
SELECT * FROM products WHERE data @> '{"in_stock": true}';
SELECT * FROM products WHERE data @> '{"specs": {"ram": 16}}';
SELECT * FROM products WHERE '{"name": "Ноутбук"}' <@ data;
SELECT * FROM products WHERE data ? 'price';
SELECT * FROM products WHERE data ? 'discontinued';
SELECT * FROM products WHERE data ?| ARRAY['price', 'sale_price'];
SELECT * FROM products WHERE data ?& ARRAY['name', 'price', 'specs'];
Изменение JSONB
UPDATE products
SET data = jsonb_set(data, '{price}', '90000')
WHERE id = 1;
UPDATE products
SET data = jsonb_set(data, '{specs, ram}', '32')
WHERE id = 1;
UPDATE products
SET data = jsonb_set(data, '{discount}', '0.1', true)
WHERE id = 1;
UPDATE products
SET data = data || '{"sale": true, "sale_price": 75000}'::jsonb
WHERE id = 1;
UPDATE products
SET data = data - 'discontinued'
WHERE id = 1;
UPDATE products
SET data = data #- '{specs, display}'
WHERE id = 1;
Функции разворачивания
SELECT key, value FROM jsonb_each('{"a": 1, "b": 2, "c": 3}'::jsonb);
SELECT key, value FROM jsonb_each_text(data) WHERE key = 'name'
FROM products;
SELECT jsonb_object_keys(data) FROM products;
SELECT elem FROM jsonb_array_elements(data -> 'tags')
FROM products;
SELECT elem FROM jsonb_array_elements_text(data -> 'tags')
FROM products;
SELECT jsonb_array_length(data -> 'tags') FROM products;
jsonb_path_query: JSON Path (PostgreSQL 12+)
SELECT jsonb_path_query(data, '$.specs.ram ? (@ > 8)')
FROM products;
SELECT jsonb_path_query_array(data, '$.tags[*]')
FROM products;
SELECT *
FROM products
WHERE jsonb_path_exists(data, '$.specs.ram ? (@ >= 16)');
Агрегация в JSONB
SELECT jsonb_agg(jsonb_build_object('id', id, 'name', name))
FROM products;
SELECT jsonb_object_agg(id::text, name)
FROM products;
SELECT jsonb_build_object(
'total', COUNT(*),
'avg_price', AVG((data->>'price')::numeric),
'categories', jsonb_agg(DISTINCT data->>'category')
)
FROM products;
Индексы для JSONB
CREATE INDEX idx_products_data ON products USING gin(data);
CREATE INDEX idx_products_data_path ON products USING gin(data jsonb_path_ops);
CREATE INDEX idx_products_price ON products ((data->>'price')::numeric);
SELECT * FROM products WHERE data @> '{"in_stock": true}';
SELECT * FROM products WHERE (data->>'price')::numeric > 10000;
Конвертация JSONB ↔ другие форматы
SELECT '{"key": "value"}'::jsonb;
SELECT to_jsonb('text'::text);
SELECT to_jsonb(users) FROM users WHERE id = 42;
SELECT data::text FROM products;
SELECT * FROM jsonb_to_record('{"name": "Bob", "age": 30}')
AS x(name TEXT, age INTEGER);
SELECT * FROM jsonb_to_recordset('[{"name": "Alice", "score": 95}, {"name": "Bob", "score": 87}]')
AS x(name TEXT, score INTEGER);
Итог: шпаргалка операторов
| Оператор | Что делает |
|---|
-> 'key' | Значение поля (JSONB) |
->> 'key' | Значение поля (TEXT) |
#> '{a,b}' | Вложенный путь (JSONB) |
@> '{...}' | Содержит объект |
? 'key' | Ключ существует |
|| | Объединить объекты |
- | Удалить ключ |
jsonb_set(...) | Установить значение |
jsonb_each(...) | Пары ключ-значение |
jsonb_array_elements(...) | Элементы массива |
@? '$.path' | JSON Path проверка |
Попробуй на практике
Тренажёр с реальными задачами — бесплатно и без регистрации
Открыть тренажёр →