JSONB Рекурсивный поиск и замена по ключу - PullRequest
0 голосов
/ 08 января 2020

При произвольном вложении документа jsonb, как все экземпляры указанного ключа c могут быть заменены другим документом.

Например:

select '{
    "good_key": {
        "critical": "info",
        "bad_key": {
            "worthless": "trash"
        }
    },
    "bad_key": {
        "more": "garbage"
    }
}'::jsonb

замена всех экземпляров "bad_key" и его содержимое, с {"substitute_key": {"some": "info"}}

В результате

'{
    "good_key": {
        "critical": "info",
        "substitute_key": {
           "some": "info"
        }
    },
    "substitute_key": {
        "some": "info"
    }
}'

1 Ответ

1 голос
/ 08 января 2020

Вы можете сделать это с помощью комбинации jsonb_each и jsonb_object_agg:

CREATE FUNCTION jsonb_replace_by_key(obj jsonb, search text, substitute jsonb) RETURNS jsonb
STRICT LANGUAGE SQL AS $$
  SELECT CASE jsonb_typeof(obj)
    WHEN 'object' THEN
      (SELECT jsonb_object_agg(key, CASE WHEN key = search
          THEN substitute
          ELSE jsonb_replace_by_key(value, search, substitute)
        END)
      FROM jsonb_each(obj))
    WHEN 'array' THEN
      (SELECT jsonb_agg(jsonb_replace_by_key(el, search, substitute))
      FROM jsonb_array_elements(obj) el)
    ELSE
      obj
 END;
$$;

Поскольку вы не хотите просто заменять значение свойства, но полностью удалите свойство и добавьте что-нибудь еще, когда оно существовало, вместо этого используйте следующий запрос в object:

SELECT jsonb_object_agg(key, jsonb_replace_by_key(value, search, substitute))
  || CASE WHEN obj ? search THEN substitute ELSE '{}' END
FROM jsonb_each(obj)
WHERE key <> search

( online demo )

...