mergedJSONPatch
Добавлено в версии: v26.8.0 Агрегирует значения JSON, выполняя их слияние по принципу «побеждает последняя запись» (last-write-wins), и реализует базовую логику слияния из RFC 7396 JSON Merge Patch на уровне путей. Агрегатная функция хранит состояние в виде троек (key, value, sorting_key), где для каждого ключа (JSON-пути) сохраняется только последняя действующая запись согласно sorting_key. Записи объектов уплощаются в дочерние пути для тех путей, которые типJSON хранит как динамические скалярные листовые узлы. Необъектные записи в родительские пути
затеняют конфликтующие с ними дочерние.
Каждый явно типизированный путь (объявленный с помощью JSON(a Map(...)), JSON(a Tuple(...)),
JSON(a Variant(...)), JSON(a Dynamic) и т. д.), обрабатывается как атомарное значение: значение пути
целиком заменяется более новым патчем, а не объединяется глубоким слиянием. Семантике глубокого слияния по RFC 7396
подчиняются только нетипизированные (динамические) скалярные пути.
Столбец sort_key определяет, какое значение будет выбрано для каждого JSON-пути. Сохраняется строка с наибольшим значением sort_key. Если у двух конфликтующих патчей значения ключа сортировки совпадают, результат зависит от порядка обработки:
побеждает патч, обработанный позже. Не стоит рассчитывать, что ORDER BY детерминированно разрешит такие ситуации.
ОГРАНИЧЕНИЯ (унаследованы от ColumnObject):
-
Удаление через null: патч
{"key": null}не удаляет ключ.ColumnObjectотбрасывает элементы со значением null при вставке, поэтому функция не может отличить “ключ отсутствует” от “ключ равен null”. -
Замена пустым объектом: патч
{"a": {}}не может заменить более старое скалярное значение или массив по путиa.ColumnObjectмолча отбрасывает пути, значением которых является пустой объект{}, поэтому более новый патч ничего не меняет, и старое значение сохраняется. -
Отсутствие типизированного пути с не-Nullable типом: если в JSON-столбце объявлен типизированный путь с
типом, не допускающим NULL (например,
JSON(a UInt32)), строка безaсохраняется со значением по умолчанию для этого типа (например,0). Агрегатная функция не может отличить “отсутствует” от “явно записано значение по умолчанию”, поэтому более новый патч безaмолча затирает более старое ненулевое значение. Чтобы избежать этого, объявляйте типизированные пути какNullable(например,JSON(a Nullable(UInt32))). Значение null в типизированном пути, допускающем NULL, интерпретируется как “путь отсутствует” и корректно пропускается. -
Все типизированные пути атомарны: каждый типизированный путь (
Map(K,V),JSON,Dynamic,Tuple(…),Variant(…),Array(…)или любой другой объявленный тип) хранится как единое значение. Агрегатная функция атомарно заменяет значение целиком, а не выполняет глубокое слияние его содержимого. Глубокое слияние по отдельным путям выполняется только для динамических (нетипизированных, скалярных) путей. -
Неоднозначность точки в ключе: тип
JSONпредставляет{"a":{"b":1}}и{"a.b":1}одним и тем же внутренним путёмa.b. Поэтому одна строка может содержать одновременноaиa.bкак независимые равноправные пути. Если более новый патч записывает толькоa, правило конфликта предка и потомка стираетa.b; если он записывает толькоa.b, то же правило стираетa. Чтобы избежать этого, задайтеjson_type_escape_dots_in_keys = 1. При этой настройке точки в ключах JSON кодируются процентной кодировкой (например,a.bпревращается вa%2Eb), что отличает их от вложенных путей и устраняет ложный конфликт.
json— JSON-столбец для агрегации.JSONsort_key— столбец со сравнимыми значениями, определяющий, какая запись имеет приоритет для каждого пути. Сохраняется строка с наибольшим значением sort_key.
JSON
Примеры
Базовое использование с ключом сортировки
Query
Response