Как правильно выгрузить иерархический справочник в JSON в 1С: разбираем ошибки рекурсии

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции баз данных 1С со сторонними системами или сайтами часто возникает задача выгрузить справочник с сохранением иерархии групп и элементов в формат JSON. Начинающие разработчики нередко пытаются решить эту задачу "в лоб" с помощью рекурсии, передавая структуру на каждый уровень вложенности. Рассмотрим подробнее типичные проблемы такого подхода и разберем по шагам, как правильно и оптимально выгрузить древовидные данные.

Анализ проблемы: почему рекурсия "зацикливается" и данные перетираются?

Проанализируем ситуацию, когда при обходе папок справочника программа зависает или на выходе формируется JSON с неверными данными. Истинная причина кроется в архитектурных ошибках и непонимании работы платформы 1С с памятью.

  1. Особенности ссылочных типов 1С. Структуры и массивы в 1С передаются по ссылке. Если мы создаем Новый Структура один раз перед вызовом функции, а затем передаем ее в рекурсию, то на всех уровнях вложенности мы модифицируем один и тот же объект в памяти. Ключи структуры постоянно перезаписываются данными самого глубокого уровня вложенности. Из-за этого кажется, что данные теряются или рекурсия зацикливается. Чтобы иерархия строилась корректно, необходимо для каждой новой папки инициализировать новую структуру внутри рекурсии.
  2. Запросы в цикле и рекурсии. Использование запроса к базе данных внутри цикла или рекурсии — это грубая ошибка. Это критически снижает производительность системы. База данных вынуждена обрабатывать множество мелких запросов, что при больших объемах справочника приведет к долгим зависаниям.

Оптимальное решение 1: Запрос с конструкцией ИТОГИ

Разберем, как избавиться от множественных запросов. Для получения всего дерева за один раз необходимо написать один запрос к справочнику с использованием конструкции ИТОГИ ПО Родитель ТОЛЬКО ИЕРАРХИЯ.

После выполнения такого запроса результат нужно обходить специальным образом, используя метод ПоГруппировкам. Посмотрим на пример:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Номенклатура.Ссылка КАК Ссылка,
    |    Номенклатура.ЭтоГруппа КАК ЭтоГруппа,
    |    Номенклатура.Родитель КАК Родитель
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |    Номенклатура.ПометкаУдаления = ЛОЖЬ
    |ИТОГИ ПО
    |    Родитель ТОЛЬКО ИЕРАРХИЯ";

РезультатЗапроса = Запрос.Выполнить();
ВыборкаГрупп = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

// Далее пишем рекурсивную функцию для обхода уже полученной выборки

В этом случае наша рекурсивная функция будет обходить не базу данных, а уже сформированную выборку в оперативной памяти. Это работает моментально.

Оптимальное решение 2: Потоковая запись JSON

Использование объектной модели (когда мы собираем всё дерево в огромную структуру или массив, а затем разом передаем в ЗаписатьJSON) при выгрузке большого справочника может привести к перерасходу оперативной памяти.

Лучшая практика — это потоковая запись JSON. Вместо формирования громоздких структур, в процессе обхода выборки мы напрямую вызываем методы объекта ЗаписьJSON. Проанализируем, как это выглядит:


ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();

// Внутри обхода выборки вызываем методы записи
ЗаписьJSON.ЗаписатьНачалоОбъекта();
ЗаписьJSON.ЗаписатьИмяСвойства("Group");
ЗаписьJSON.ЗаписатьЗначение(Строка(Выборка.Ссылка));

ЗаписьJSON.ЗаписатьИмяСвойства("Nomencl");
ЗаписьJSON.ЗаписатьНачалоМассива();
// ... запись элементов ...
ЗаписьJSON.ЗаписатьКонецМассива();

ЗаписьJSON.ЗаписатьКонецОбъекта();

Этот подход последовательно пишет данные, практически не потребляя оперативную память, что делает вашу обработку стабильной при любых объемах номенклатуры.

Альтернативные подходы: Дерево значений и Сериализатор XDTO

Если цель задачи — выгрузить данные для другой базы 1С, ручное формирование структур можно вообще исключить.

  1. Выгрузка в Дерево Значений. Вы можете выгрузить результат запроса в готовое ДеревоЗначений методом Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией). Написать рекурсивный обход строк готового дерева в памяти гораздо безопаснее.
  2. Использование Сериализатора XDTO. В платформе 1С встроен объект СериализаторXDTO, который умеет автоматически выгружать ссылки и объекты (справочники, документы) в формат JSON со всеми реквизитами. Достаточно выгрузить нужные элементы в массив и передать их сериализатору, который сам развернет поля согласно метаданным вашей конфигурации.
  3. Раздельная выгрузка. Если иерархия в одном файле не критична, выгружайте данные за два шага: сначала сформируйте массив (или JSON) всех групп, а затем массив всех элементов с указанием их уникального идентификатора родителя. Принимающая сторона сама восстановит структуру по полям ссылок.

Применяя эти методы, вы избежите зависаний рекурсии, исключите лишнюю нагрузку на сервер БД и сделаете ваш код надежным и эффективным.

← На главную