Добавить элемент в объект JSON в Postgres

у меня есть текстовое поле в базе данных (postgres 9.2.1) с JSON blob в нем. Это выглядит чем-то похожим на это, за исключением всех на одной строке, очевидно:

{
  "keyword": {
    "checked": "1",
    "label": "Keyword"
  },
  "agency_name": {
    "checked": "0",
    "label": "Agency Name"
  }
}

мне нужно добавить элемент в массив json, чтобы он выглядел так:

{
  "keyword": {
    "checked": "1",
    "label": "Keyword"
  },
  "something_new": {
    "checked": "1",
    "label": "Something New"
  },
  "agency_name": {
    "checked": "0",
    "label": "Agency Name"
  }
}

меня не так беспокоит размещение нового элемента массива. Это может быть после agency_name. Есть ли простой способ сделать это в postgres?

6 ответов


даже у меня была такая же проблема, я хотел динамически добавлять новые элементы в jsonb[].

предположим column_jsonb [] = [{"name": "xyz", "age": "12"}]

UPDATE table_name
   SET column_jsonb[] = array_append(column_jsonb[],'{"name":"abc","age":"22"}');

результат: [{"имя": "xyz","возраст":"12"}, {"имя":"abc","Возраст": "22"}]


Если обновление до PG9.5.1, тогда вы можете использовать sql operate || для объединения jsonb, пример

select '{"a":1}'::jsonb || '{"a":2, "b":2}'::jsonb

вернутся {"a": 2, "b": 2}

Если вы не можете перейти на pg9.5.1, ИМХО, выполнение работы в вашем коде будет лучшим выбором. Вы можете разобрать старую строку jsonb как карту, а затем обновить карту, затем преобразовать в строку и обновить db-record.


PostgreSQL еще не имеет много функций поддержки JSON: все, что я вижу, это такие, как array_to_json, Что может быть полезно, если существует соответствующий способ преобразования исходного JSON в массив, которым вы можете манипулировать, чтобы добавить этот дополнительный элемент перед преобразованием обратно в JSON.

возможно, лучше всего использовать язык PL для управления JSON. Одним из очевидных будет PLV8, который обеспечивает функциональность программирования JavaScript в В PostgreSQL. Вы напишете пользовательскую функцию в JavaScript, которая будет манипулировать JSON blob соответственно:

конечно, многие другие языки PL, такие как Java, Python или Perl, могут быть так же хороши в работе с данными JSON и, возможно, проще установить в вашей системе. Пользовательские функции могут быть записаны в каждом из них, если они настроены.


версия 9.5 предоставляет jsonb_set функция с create_missing=TRUE. В любых других случаях используйте следующий хак для добавления информации:

SELECT (trim( trailing '}' from data::text) || ', "c":2}')::json

чтобы добавить / заменить новое значение, используя более правильный способ:

UPDATE t
SET data=t3.data

FROM t AS t1
INNER JOIN
(
  SELECT id, json_object_agg(t.k,t.v)
  FROM
    (
      SELECT *
      FROM (SELECT id, json_object_keys(data) as k, data->json_object_keys(data) as v FROM t) as t2
      WHERE t.k != 'c'

      UNION ALL
      SELECT id, 'c'::text as k, '"new value"'::json as v FROM t1
    ) as t3
  GROUP by id
) as t4 ON (t1.id=t4.id)

удалить ключ:

UPDATE t
SET data=t3.data

FROM t AS t1
INNER JOIN
(
  SELECT id, json_object_agg(t.k,t.v)
  FROM (SELECT id, json_object_keys(data) as k, data->json_object_keys(data) as v FROM t) as t2
  WHERE t.k != 'c'
  GROUP by id
) as t4 ON (t1.id=t4.id)

У меня была именно эта проблема. Это решение является довольно "чистой" манипуляцией объектами, и я предпочитаю функции " sql " plpgsql. Главное-дезагрегировать с помощью json_each-дать вам запись - а затем создать запись из

CREATE OR REPLACE FUNCTION json_extend_object(
    input_object json,
    append_key text,
    append_object json)
  RETURNS json AS
$BODY$
    select json_object_agg (((json_val)::record).key, ((json_val)::record).value)
    from (
        select json_val 
        from (select json_each (input_object) as json_val) disaggr
        where ((json_val::record).key != append_key)
        union 
        select newvals
        from (
            select append_key, append_object
        ) newvals
    ) to_rows;
$BODY$
  LANGUAGE sql IMMUTABLE
  ;

использовать || объединить jsonb и установить для него значение

пример:

начало:

в таблице a:

id / info

1 / {"aa":"bb"}

2 / {"aa":"cc"}

после выполнения:

update a set info = info::jsonb || ('{"id":}' || id || '}' )::jsonb 

выдает:

id / info

1 / {"aa": "bb", "id": 1}

2 | {"aa": "cc", "id": 2}

something_else:

  1. использовать - ‘key’ удалить элемент в jsonb
  2. merge заменит origin one, если два jsonb имеют одинаковый ключ