Postgres 9.4 데이터 유형 JSONB에 대한 문서를 살펴보면 JSONB 열에 대한 업데이트 방법을 즉시 알 수 없습니다.
JSONB 유형 및 기능에 대한 문서 :
http://www.postgresql.org/docs/9.4/static/functions-json.html
http://www.postgresql.org/docs/9.4/static/datatype-json.html
예를 들어 다음과 같은 기본 테이블 구조가 있습니다.
CREATE TABLE test(id serial, data jsonb);
다음과 같이 삽입이 쉽습니다.
INSERT INTO test(data) values ('{"name": "my-name", "tags": ["tag1", "tag2"]}');
이제 ‘데이터’열을 어떻게 업데이트합니까? 잘못된 구문입니다.
UPDATE test SET data->'name' = 'my-other-name' WHERE id = 1;
내가 놓친 것이 분명한 곳에 문서화되어 있습니까? 감사.
답변
관계형 데이터베이스 내에서 조작하려는 구조화 된 일반 데이터에 JSON 문서를 사용하지 않는 것이 이상적입니다. 용도 정규화 관계형 디자인을 대신.
JSON은 주로 RDBMS 내부에서 조작 할 필요가없는 전체 문서를 저장하기위한 것입니다. 관련 :
Postgres에서 행을 업데이트하면 항상 전체 행 의 새 버전이 작성 됩니다. 이것이 Postgres의 MVCC 모델 의 기본 원칙입니다 . 성능 측면에서 JSON 객체 내에서 하나의 데이터를 변경하는지 또는 모든 데이터를 변경하는지는 중요하지 않습니다. 새로운 버전의 행을 작성해야합니다.
JSON 데이터는 테이블에 저장 될 때 다른 데이터 유형과 동일한 동시성 제어 고려 사항이 적용됩니다. 큰 문서를 저장하는 것이 가능하지만 모든 업데이트는 전체 행에서 행 수준 잠금을 얻습니다. 업데이트 트랜잭션 간의 잠금 경합을 줄이려면 JSON 문서를 관리 가능한 크기로 제한하는 것이 좋습니다. 이상적으로 JSON 문서는 각각 비즈니스 규칙이 지시하는 원자 데이텀을 나타내야하며 독립적으로 수정할 수있는 더 작은 데이텀으로 더 이상 세분화 될 수 없습니다.
그것의 요점은 : 수정 아무것도 JSON 개체 내부를, 당신은 칼럼에 수정 된 객체를 할당해야합니다. Postgres json
는 스토리지 기능 외에도 데이터 를 구축하고 조작 할 수있는 제한된 수단을 제공합니다. 버전 9.2 이후의 모든 새로운 릴리스에서 도구의 수가 대폭 향상되었습니다. 그러나 주체는 여전히 남아 있습니다. 항상 수정 된 객체를 열에 할당해야하며 Postgres는 항상 모든 업데이트에 대해 새 행 버전을 작성합니다.
Postgres 9.3 이상의 도구로 작업하는 방법에 대한 몇 가지 기술 :
이 답변은 SO의 모든 내 다른 답변 많은 downvotes로에 대해 끌었다 함께 . 사람들은이 아이디어를 좋아하지 않는 것 같습니다. 표준화 된 디자인은 비 동적 데이터보다 우수합니다. Craig Ringer의이 훌륭한 블로그 게시물은 다음과 같이 자세히 설명합니다.
답변
Postgresql 9.5로 업그레이드 할 수 있다면 jsonb_set
다른 사람들이 언급했듯이 명령을 사용할 수 있습니다.
다음의 각 SQL 문에서 where
간결성을 위해 절을 생략했습니다. 분명히 다시 추가하고 싶을 것입니다.
업데이트 이름 :
UPDATE test SET data = jsonb_set(data, '{name}', '"my-other-name"');
태그를 추가하거나 제거하는 것이 아니라 태그를 교체하십시오.
UPDATE test SET data = jsonb_set(data, '{tags}', '["tag3", "tag4"]');
두 번째 태그 교체 (0 색인) :
UPDATE test SET data = jsonb_set(data, '{tags,1}', '"tag5"');
태그를 추가합니다 ( 999 개 미만 의 태그 가있는 한 작동합니다. 인수를 999에서 1000 이상으로 변경하면 오류가 발생합니다 . Postgres 9.5.3에서는 더 이상 발생 하지 않으며 더 큰 인덱스를 사용할 수 있음) :
UPDATE test SET data = jsonb_set(data, '{tags,999999999}', '"tag6"', true);
마지막 태그를 제거하십시오.
UPDATE test SET data = data #- '{tags,-1}'
복잡한 업데이트 (마지막 태그 삭제, 새 태그 삽입 및 이름 변경) :
UPDATE test SET data = jsonb_set(
jsonb_set(data #- '{tags,-1}', '{tags,999999999}', '"tag3"', true),
'{name}', '"my-other-name"');
이러한 각 예에서 실제로 JSON 데이터의 단일 필드를 업데이트하지는 않습니다. 대신 임시 수정 버전의 데이터를 만들고 수정 된 버전을 다시 열에 할당합니다. 실제로 결과는 동일해야하지만이를 염두에두면 마지막 예와 같이 복잡한 업데이트가 더 이해하기 쉬워집니다.
복잡한 예에는 세 가지 변형과 세 가지 임시 버전이 있습니다. 먼저 마지막 태그가 제거됩니다. 그런 다음 새 태그를 추가하여 해당 버전이 변환됩니다. 다음으로, 두 번째 버전은 name
필드 를 변경하여 변환됩니다 . data
열의 값 이 최종 버전으로 바뀝니다.
답변
이것은 9.4에서 작동 하는 기존 확장 jsonbx 를 기반으로 Andrew Dunstan에 의해 jsonb_set 형식으로 9.5에 제공됩니다.
답변
이 문제가 발생하고 매우 빠른 수정을 원하고 (9.4.5 또는 이전 버전에 붙어있는) 사람들을 위해 여기 내가 한 일이 있습니다.
테스트 테이블 생성
CREATE TABLE test(id serial, data jsonb);
INSERT INTO test(data) values ('{"name": "my-name", "tags": ["tag1", "tag2"]}');
jsonb 특성의 이름을 변경하는 명령문 업데이트
UPDATE test
SET data = replace(data::TEXT,'"name":','"my-other-name":')::jsonb
WHERE id = 1;
궁극적으로 허용되는 답변은 jsonb 객체의 개별 부분 (9.4.5 이하)을 수정할 수 없다는 점에서 정확합니다. 그러나 jsonb 객체를 문자열 (:: TEXT)로 캐스트 한 다음 문자열을 조작하고 jsonb 객체 (:: jsonb)로 다시 캐스트 할 수 있습니다.
두 가지 중요한 경고가 있습니다
- 이것은 json에서 “name”이라는 모든 속성을 대체합니다 (같은 이름을 가진 여러 속성이있는 경우)
- 9.5를 사용하는 경우 jsonb_set만큼 효율적이지 않습니다.
즉, jsonb 객체의 내용에 대한 스키마를 업데이트 해야하는 상황이 발생했으며 이것이 원래 포스터가 요구하는 것을 정확하게 달성하는 가장 간단한 방법이었습니다.
답변
이 질문은 postgres 9.4와 관련하여 요청되었지만이 질문에 나오는 새로운 뷰어는 postgres 9.5에서 JSONB 필드에 대한 하위 문서 만들기 / 업데이트 / 삭제 작업이 데이터베이스에서 기본적으로 확장없이 지원됨을 알고 있어야합니다. 기능.
참조 : JSONB은 연산자와 함수를 수정
답변
‘name’속성을 업데이트하십시오.
UPDATE test SET data=data||'{"name":"my-other-name"}' WHERE id = 1;
예를 들어 ‘name’및 ‘tags’속성을 제거하려면 다음을 수행하십시오.
UPDATE test SET data=data-'{"name","tags"}'::text[] WHERE id = 1;
답변
Postgres 9.4에서 재귀 적으로 작동하는 작은 함수를 작성했습니다. 나는 같은 문제가 있었다 (Postgres 9.5 에서이 두통 중 일부를 해결 했음). 어쨌든 여기 기능이 있습니다 (나는 그것이 당신에게 잘 작동하기를 바랍니다) :
CREATE OR REPLACE FUNCTION jsonb_update(val1 JSONB,val2 JSONB)
RETURNS JSONB AS $$
DECLARE
result JSONB;
v RECORD;
BEGIN
IF jsonb_typeof(val2) = 'null'
THEN
RETURN val1;
END IF;
result = val1;
FOR v IN SELECT key, value FROM jsonb_each(val2) LOOP
IF jsonb_typeof(val2->v.key) = 'object'
THEN
result = result || jsonb_build_object(v.key, jsonb_update(val1->v.key, val2->v.key));
ELSE
result = result || jsonb_build_object(v.key, v.value);
END IF;
END LOOP;
RETURN result;
END;
$$ LANGUAGE plpgsql;
다음은 샘플 사용입니다.
select jsonb_update('{"a":{"b":{"c":{"d":5,"dd":6},"cc":1}},"aaa":5}'::jsonb, '{"a":{"b":{"c":{"d":15}}},"aa":9}'::jsonb);
jsonb_update
---------------------------------------------------------------------
{"a": {"b": {"c": {"d": 15, "dd": 6}, "cc": 1}}, "aa": 9, "aaa": 5}
(1 row)
보시다시피 깊이 분석하고 필요한 경우 값을 업데이트 / 추가하십시오.