명령어/DB

[PostgreSQL] jsonb_set / || 로 JSON 일부만 갱신하기

jykim23 2026. 8. 1. 19:51
반응형

설치·접속: PostgreSQL 설치와 접속

부제: settings jsonb 안의 notify.email 하나만 false로 바꾸고 싶은데, 전체 JSON을 통째로 다시 써서 UPDATE하기는 싫을 때

-- jsonb_set(원본, 경로배열, 새값jsonb) — 깊은 값 하나만 교체
SELECT jsonb_set(settings, '{notify,email}', 'false') FROM m4_users WHERE id=1;
-- || 는 최상위 키를 병합/추가 (있으면 덮고, 없으면 추가)
SELECT settings || '{"theme":"solarized","beta":true}' FROM m4_users WHERE id=1;
 {"lang": "ko", "plan": "pro", "theme": "dark", "notify": {"sms": false, "push": true, "email": false}}

 {"beta": true, "lang": "ko", "plan": "pro", "theme": "solarized", "notify": {"sms": false, "push": true, "email": true}}

둘은 역할이 다르다. jsonb_set경로를 콕 집어 깊은 곳 한 값만 바꾸고 나머지는 그대로 둔다. ||최상위 레벨 병합이라 여러 키를 한 번에 덮거나 추가할 때 편하다. 함정: ||는 최상위만 병합해서 settings || '{"notify":{"email":false}}'를 하면 notify 객체 전체가 통째로 교체된다(sms·push가 사라진다). 중첩 안쪽만 바꾸려면 반드시 jsonb_set으로 경로를 지정한다. 실제 반영은 UPDATE에 넣는다.

UPDATE m4_users SET settings = jsonb_set(settings, '{plan}', '"enterprise"')
WHERE id=2 RETURNING settings;
 {"lang": "ko", "plan": "enterprise", "theme": "light", "notify": {"sms": false, "email": false}}

이렇게도 쓴다

키 삭제는 - (최상위), 깊은 경로 삭제는 #-.

SELECT settings - 'plan'        FROM m4_users WHERE id=1;  -- plan 제거
SELECT settings #- '{notify,sms}' FROM m4_users WHERE id=1;  -- notify.sms 제거

 

경로가 없으면 기본적으로 새로 만든다(create_missing = true).

SELECT jsonb_set('{"a":1}', '{b}', '9');   -- {"a": 1, "b": 9}

 

넷째 인자를 false로 주면 없는 경로는 무시한다 — "있을 때만 갱신".

SELECT jsonb_set('{"a":1}', '{b}', '9', false);   -- {"a": 1} 그대로

 

값이 NULL일 때 동작을 고르는 jsonb_set_lax — 여기선 키 자체를 삭제.

SELECT jsonb_set_lax('{"a":1}', '{a}', NULL, true, 'delete_key');  -- {}

 

여러 필드를 한 UPDATE에서 각각 갱신 — jsonb_set 중첩. (조합: 중첩 호출)

UPDATE m4_users
SET settings = jsonb_set(jsonb_set(settings,'{theme}','"dim"'),'{lang}','"en"')
WHERE id=1 RETURNING settings;
반응형