Jeśli JSONB to magiczna skrzynia, do której wrzucamy dane, to || i jsonb_concat() to narzędzia, które pozwalają te skrzynie łączyć albo zmieniać ich zawartość. W realu możesz potrzebować połączyć kilka obiektów JSON, dodać dane z jednego do drugiego albo połączyć tablice w jedną listę.
Na przykład, wyobraź sobie, że masz dwa obiekty JSONB:
{"name": "Alice", "age": 25}
i
{"city": "Wonderland", "hobbies": ["czytanie", "szachy"]}
Chcesz dostać:
{"name": "Alice", "age": 25, "city": "Wonderland", "hobbies": ["czytanie", "szachy"]}
Albo połączyć dwie tablice JSONB:
[1, 2, 3]
i
[4, 5, 6]
żeby wynik wyglądał tak:
[1, 2, 3, 4, 5, 6]
To wszystko ogarniesz przez || albo jsonb_concat(). Zobaczmy jak to działa.
Operator || do łączenia JSONB
Operator || pozwala łączyć dwa obiekty lub tablice JSONB w PostgreSQL. Jest prosty, szybki i łatwy w użyciu. Oto główne zasady działania:
- Jeśli łączysz dwa obiekty JSONB, wynikowy obiekt będzie miał klucze i wartości z obu obiektów.
- Jeśli klucze się powtarzają, wartość z prawego operanda nadpisuje wartość z lewego.
- Jeśli łączysz tablice JSONB, elementy lewej i prawej tablicy są łączone w jedną tablicę.
Przykład 1: Łączenie dwóch obiektów JSONB
SELECT '{"name": "Alice", "age": 25}'::jsonb || '{"city": "Wonderland", "hobbies": ["czytanie", "szachy"]}'::jsonb AS merged_object;
Wynik:
{"name": "Alice", "age": 25, "city": "Wonderland", "hobbies": ["czytanie", "szachy"]}
Przykład 2: Aktualizacja wartości przy powtarzających się kluczach
SELECT '{"name": "Alice", "age": 25}'::jsonb || '{"age": 30, "city": "Wonderland"}'::jsonb AS updated_object;
Wynik:
{"name": "Alice", "age": 30, "city": "Wonderland"}
Zwróć uwagę, że wartość klucza "age" z prawego obiektu nadpisała wartość z lewego.
Przykład 3: Łączenie tablic
SELECT '[1, 2, 3]'::jsonb || '[4, 5, 6]'::jsonb AS merged_array;
Wynik:
[1, 2, 3, 4, 5, 6]
Funkcja jsonb_concat() do łączenia JSONB
Funkcja jsonb_concat() działa podobnie jak operator ||, ale daje więcej elastyczności, jeśli chcesz jej użyć w funkcjach, triggerach albo dynamicznych zapytaniach. Przyjmuje dwa argumenty typu JSONB i zwraca połączony wynik.
Przykład: użycie jsonb_concat()
SELECT jsonb_concat('{"a": 1, "b": 2}'::jsonb, '{"b": 3, "c": 4}'::jsonb) AS combined;
Wynik:
{"a": 1, "b": 3, "c": 4}
Łączenie obiektów i tablic: szczegóły i niuanse
Łącząc obiekty z powtarzającymi się kluczami, pamiętaj, że wartości z prawego obiektu mają priorytet.
Na przykład:
SELECT '{"key1": "wartosc1"}'::jsonb || '{"key1": "wartosc2"}'::jsonb AS result;
Wynik:
{"key1": "wartosc2"}
Jeśli nie chcesz nadpisywać wartości, trzymaj takie dane pod osobnymi kluczami albo użyj innego podejścia (np. tablicy).
A tablice zawsze są łączone przez dodanie elementów z prawej tablicy do lewej. Na przykład:
SELECT '["a", "b"]'::jsonb || '["c", "d"]'::jsonb AS result;
Wynik:
["a", "b", "c", "d"]
Jeśli w tablicy są obiekty, kolejność obiektów zostaje zachowana:
SELECT '[{"id": 1}, {"id": 2}]'::jsonb || '[{"id": 3}]'::jsonb AS result;
Wynik:
[{"id": 1}, {"id": 2}, {"id": 3}]
Praktyczne przykłady
Aktualizacja profilu użytkownika. Załóżmy, że mamy tabelę users, gdzie profile są trzymane w formacie JSONB:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
profile JSONB
);
INSERT INTO users (profile) VALUES ('{"name": "Alice", "age": 25}');
Teraz chcemy dodać miasto zamieszkania:
UPDATE users
SET profile = profile || '{"city": "Wonderland"}'
WHERE id = 1;
Wynik zapytania:
{"name": "Alice", "age": 25, "city": "Wonderland"}
Łączenie danych o zamówieniach. Załóżmy, że mamy tabelę orders:
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
details JSONB
);
INSERT INTO orders (details) VALUES ('{"items": [{"product": "laptop", "quantity": 1}]}');
Teraz dodajemy kolejny produkt do zamówienia:
UPDATE orders
SET details = jsonb_set(
details,
'{items}',
details->'items' || '[{"product": "mysz", "quantity": 2}]'::jsonb
)
WHERE id = 1;
Wynik zapytania:
{"items": [{"product": "laptop", "quantity": 1}, {"product": "mysz", "quantity": 2}]}
Różnice między || a jsonb_concat()
Funkcjonalnie operator || i funkcja jsonb_concat() są identyczne. Używaj ||, jeśli piszesz proste zapytania, bo zapis jest krótszy. Funkcja jsonb_concat() jest wygodna, gdy musisz jawnie wywołać ją w programie albo triggerze.
Typowe błędy i jak ich unikać
Błąd: próba połączenia niekompatybilnych typów.
SELECT '{"key": "wartosc"}'::jsonb || '["wartosc"]'::jsonb;
Wynik:
ERROR: cannot concatenate jsonb objects and arrays
Tu po lewej masz obiekt, a po prawej tablicę — PostgreSQL nie ogarnia takiego połączenia. Żeby operacja się udała, oba operandy muszą być tego samego typu: albo dwa obiekty, albo dwie tablice.
Przeoczenie: brak indeksów przy pracy z JSONB
Jeśli często filtrujesz dane po wartościach w polach JSONB, a nie masz indeksów — zapytania mogą mocno zamulać. To nie jest błąd w klasycznym sensie, ale skutki dla wydajności są bardzo odczuwalne. Nie zapomnij o GIN-indeksach:
CREATE INDEX idx_profile_data ON employees USING gin(profile);
GO TO FULL VERSION