JSON 오브젝트 합치기와 수정: || 연산자와 jsonb_concat() 함수
JSONB가 마치 마법 상자라면, ||랑 jsonb_concat()는 그 상자들을 합치거나 내용물을 바꿔주는 도구야. 실제로 여러 개의 JSON 오브젝트를 합치거나, 한 오브젝트에서 다른 오브젝트로 데이터를 추가하거나, 배열을 하나의 리스트로 합쳐야 할 때가 있지.
예를 들어, 두 개의 JSONB 오브젝트가 있다고 해보자:
{"name": "Alice", "age": 25}
그리고
{"city": "Wonderland", "hobbies": ["reading", "chess"]}
이렇게 만들고 싶을 때:
{"name": "Alice", "age": 25, "city": "Wonderland", "hobbies": ["reading", "chess"]}
또는 두 개의 JSONB 배열을 합치고 싶을 때:
[1, 2, 3]
그리고
[4, 5, 6]
결과가 이렇게 나오게:
[1, 2, 3, 4, 5, 6]
이런 건 전부 ||나 jsonb_concat()로 할 수 있어. 이제 어떻게 하는지 알아보자.
JSONB 합치기용 || 연산자
|| 연산자는 PostgreSQL에서 두 개의 JSONB 오브젝트나 배열을 합칠 때 써. 간단하고, 빠르고, 쓰기 쉬워. 동작 규칙은 이래:
- 두 JSONB 오브젝트를 합치면, 결과 오브젝트는 양쪽 오브젝트의 키랑 값을 다 가져와.
- 키가 겹치면, 오른쪽 오퍼랜드의 값이 왼쪽 값을 덮어써.
- JSONB 배열을 합치면, 왼쪽 배열과 오른쪽 배열의 요소가 하나의 배열로 합쳐져.
예제 1: 두 JSONB 오브젝트 합치기
SELECT '{"name": "Alice", "age": 25}'::jsonb || '{"city": "Wonderland", "hobbies": ["reading", "chess"]}'::jsonb AS merged_object;
결과:
{"name": "Alice", "age": 25, "city": "Wonderland", "hobbies": ["reading", "chess"]}
예제 2: 키가 겹칠 때 값 업데이트
SELECT '{"name": "Alice", "age": 25}'::jsonb || '{"age": 30, "city": "Wonderland"}'::jsonb AS updated_object;
결과:
{"name": "Alice", "age": 30, "city": "Wonderland"}
여기서 "age" 키의 값이 오른쪽 오브젝트 값으로 바뀐 거 주목해.
예제 3: 배열 합치기
SELECT '[1, 2, 3]'::jsonb || '[4, 5, 6]'::jsonb AS merged_array;
결과:
[1, 2, 3, 4, 5, 6]
JSONB 합치기용 jsonb_concat() 함수
jsonb_concat() 함수는 || 연산자랑 비슷하게 동작하지만, 함수라서 함수 안이나 트리거, 동적 쿼리에서 쓰기 더 편해. 인자로 JSONB 두 개를 받아서 합쳐진 결과를 반환해.
예제: jsonb_concat() 사용
SELECT jsonb_concat('{"a": 1, "b": 2}'::jsonb, '{"b": 3, "c": 4}'::jsonb) AS combined;
결과:
{"a": 1, "b": 3, "c": 4}
오브젝트와 배열 합치기: 특징과 주의점
키가 겹치는 오브젝트를 합칠 때는 오른쪽 오브젝트의 값이 우선이라는 걸 기억해야 해.
예를 들어:
SELECT '{"key1": "value1"}'::jsonb || '{"key1": "value2"}'::jsonb AS result;
결과:
{"key1": "value2"}
값이 덮어써지는 걸 피하고 싶으면, 각각 다른 키에 저장하거나, 아니면 배열 같은 다른 방법을 써야 해.
그리고 배열은 항상 오른쪽 배열의 요소가 왼쪽 배열 뒤에 붙어서 합쳐져. 예를 들면:
SELECT '["a", "b"]'::jsonb || '["c", "d"]'::jsonb AS result;
결과:
["a", "b", "c", "d"]
배열 안에 오브젝트가 있어도, 순서는 그대로 유지돼:
SELECT '[{"id": 1}, {"id": 2}]'::jsonb || '[{"id": 3}]'::jsonb AS result;
결과:
[{"id": 1}, {"id": 2}, {"id": 3}]
실전 예제
유저 프로필 업데이트하기. 예를 들어 users 테이블에 프로필이 JSONB로 저장돼 있다고 하자:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
profile JSONB
);
INSERT INTO users (profile) VALUES ('{"name": "Alice", "age": 25}');
이제 거주 도시를 추가하고 싶을 때:
UPDATE users
SET profile = profile || '{"city": "Wonderland"}'
WHERE id = 1;
쿼리 결과:
{"name": "Alice", "age": 25, "city": "Wonderland"}
주문 데이터 합치기. 이번엔 orders 테이블이 있다고 해보자:
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
details JSONB
);
INSERT INTO orders (details) VALUES ('{"items": [{"product": "laptop", "quantity": 1}]}');
여기에 상품을 하나 더 추가하고 싶으면:
UPDATE orders
SET details = jsonb_set(
details,
'{items}',
details->'items' || '[{"product": "mouse", "quantity": 2}]'::jsonb
)
WHERE id = 1;
쿼리 결과:
{"items": [{"product": "laptop", "quantity": 1}, {"product": "mouse", "quantity": 2}]}
||와 jsonb_concat()의 차이
기능적으로 || 연산자랑 jsonb_concat() 함수는 똑같아. 간단한 쿼리엔 ||가 더 짧고 편하고, 함수로 명확하게 호출해야 할 땐 jsonb_concat()가 좋아.
흔한 실수와 예방법
실수: 타입이 안 맞는 걸 합치려고 할 때.
SELECT '{"key": "value"}'::jsonb || '["value"]'::jsonb;
결과:
ERROR: cannot concatenate jsonb objects and arrays
왼쪽은 오브젝트, 오른쪽은 배열이라 PostgreSQL이 그냥 합칠 수 없어. 둘 다 오브젝트거나, 둘 다 배열이어야 해.
실수: JSONB 쿼리할 때 인덱스 안 쓰는 경우
JSONB 필드 안의 값으로 자주 필터링하는데 인덱스가 없으면, 쿼리가 엄청 느려질 수 있어. 이건 전통적인 의미의 에러는 아니지만, 성능에 큰 영향을 줘. 꼭 GIN 인덱스를 써줘:
CREATE INDEX idx_profile_data ON employees USING gin(profile);
GO TO FULL VERSION