Как выгрузить массив документов с табличными частями в формат JSON

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

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

Почему возникает ошибка «Неверный порядок записи JSON»?

Разберем ситуацию: вы пытаетесь использовать СериализаторXDTO.ЗаписатьJSON внутри цикла для каждого документа. При этом вы уже открыли объект ЗаписьJSON. Проблема заключается в том, что СериализаторXDTO при вызове метода записи пытается создать законченный JSON-узел. Если вы просто вызываете его в цикле, он «не понимает», что эти объекты должны быть частью одного массива. Чтобы JSON-файл был валидным, он должен иметь четкую структуру: либо один корневой объект, либо один корневой массив.

Проанализируем способы решения этой задачи — от простых до наиболее производительных.

Способ 1. Формирование структуры данных вручную (Массив структур)

Это самый гибкий и популярный метод. Мы подготавливаем данные в виде обычных коллекций 1С (Массив и Структура), а затем одной командой превращаем их в JSON. Платформа 1С умеет автоматически преобразовывать эти типы в соответствующие элементы JSON (массивы [] и объекты {}). Для автоматизации формирования программного кода можно использовать инструмент для валидации и генерации кода 1С по JSON-структурам.

Рассмотрим пример кода, который собирает данные документов в массив структур:


Процедура ВыгрузитьДокументыВJSON(ДатаНачала, ДатаОкончания, ПутьКФайлу)
    
    // 1. Подготавливаем массив для хранения всех документов
    МассивДокументов = Новый Массив;
    
    // 2. Получаем данные запросом (правильный подход — сразу все поля)
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЧекККМ.Ссылка КАК Ссылка,
    |	ЧекККМ.Номер КАК Номер,
    |	ЧекККМ.Дата КАК Дата,
    |	ЧекККМ.Товары.(
    |		Номенклатура.Наименование КАК ТоварНаименование,
    |		Количество КАК Количество,
    |		Цена КАК Цена,
    |		Сумма КАК Сумма
    |	) КАК ТЧ_Товары
    |ИЗ
    |	Документ.ЧекККМ КАК ЧекККМ
    |ГДЕ
    |	ЧекККМ.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания";
    
    Запрос.УстановитьПараметр("ДатаНачала", ДатаНачала);
    Запрос.УстановитьПараметр("ДатаОкончания", ДатаОкончания);
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();
    
    Пока Выборка.Следующий() Цикл
        
        // Создаем структуру для одного документа (шапка)
        ДанныеДокумента = Новый Структура;
        ДанныеДокумента.Вставить("ID", Строка(Выборка.Ссылка.УникальныйИдентификатор()));
        ДанныеДокумента.Вставить("Number", Выборка.Номер);
        ДанныеДокумента.Вставить("Date", Выборка.Дата);
        
        // Обрабатываем табличную часть
        МассивСтрокТЧ = Новый Массив;
        ВыборкаТЧ = Выборка.ТЧ_Товары.Выбрать();
        
        Пока ВыборкаТЧ.Следующий() Цикл
            СтруктураСтроки = Новый Структура;
            СтруктураСтроки.Вставить("Item", ВыборкаТЧ.ТоварНаименование);
            СтруктураСтроки.Вставить("Quantity", ВыборкаТЧ.Количество);
            СтруктураСтроки.Вставить("Price", ВыборкаТЧ.Цена);
            СтруктураСтроки.Вставить("Total", ВыборкаТЧ.Сумма);
            
            МассивСтрокТЧ.Добавить(СтруктураСтроки);
        КонецЦикла;
        
        ДанныеДокумента.Вставить("Items", МассивСтрокТЧ);
        
        // Добавляем документ в общий массив
        МассивДокументов.Добавить(ДанныеДокумента);
        
    КонецЦикла;
    
    // 3. Записываем весь массив в файл
    ЗаписьJSON = Новый ЗаписьJSON;
    ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(, Символы.Таб);
    ЗаписьJSON.ОткрытьФайл(ПутьКФайлу, , , ПараметрыЗаписи);
    
    // Используем встроенную функцию ЗаписатьJSON для сериализации всей структуры
    ЗаписатьJSON(ЗаписьJSON, МассивДокументов);
    
    ЗаписьJSON.Закрыть();
    
КонецПроцедуры

В данном примере мы используем вложенную выборку в запросе. Это позволяет за один сеанс работы с базой данных получить и заголовки документов, и их строки, что гораздо быстрее, чем получать объект через ПолучитьОбъект() в цикле.

Способ 2. Использование Сериализатора XDTO для потоковой записи

Если вам необходимо выгрузить объекты именно в формате XDTO (со служебными полями типа #type и #value), или документов слишком много, чтобы держать их все в памяти в виде массива структур, используйте потоковую запись. Выясним, как правильно организовать этот процесс, чтобы не получить ошибку порядка записи.

Ключевой момент — ручное управление началом и концом массива в ЗаписьJSON.


Процедура ВыгрузитьЧерезXDTO(МассивСсылок, ПутьКФайлу)
    
    ЗаписьJSON = Новый ЗаписьJSON;
    ЗаписьJSON.ОткрытьФайл(ПутьКФайлу);
    
    // Явно указываем начало массива в JSON
    ЗаписьJSON.ЗаписатьНачалоМассива();
    
    Для Каждого Ссылка Из МассивСсылок Цикл
        
        // Получаем объект документа (внимание: это создает нагрузку при больших объемах!)
        ОбъектДокумента = Ссылка.ПолучитьОбъект();
        
        // Сериализатор запишет один объект внутрь текущего массива
        СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, ОбъектДокумента, НазначениеТипаXML.Явное);
        
    КонецЦикла;
    
    // Явно указываем конец массива
    ЗаписьJSON.ЗаписатьКонецМассива();
    
    ЗаписьJSON.Закрыть();
    
КонецПроцедуры

Важное замечание: Метод СериализаторXDTO.ЗаписатьJSON выгружает объект «как есть» согласно его схеме. Это означает, что в JSON попадут абсолютно все реквизиты и все табличные части документа. Если вам нужна только часть данных, лучше использовать Способ 1.

Анализируем производительность: Запросы в цикле

Одной из главных ошибок, упомянутых в обсуждении на форуме, является получение данных через «точку» (например, Выборка.Ссылка.Номер или Для Каждого Строка ИЗ Выборка.Ссылка.Товары). Проанализируем, почему это плохо:

  1. Лишние запросы: Каждый раз, когда вы обращаетесь к Ссылка.Реквизит, система выполняет отдельный неявный запрос к базе данных.
  2. Чтение лишних данных: При вызове ПолучитьОбъект() 1С считывает из базы вообще все данные документа, включая все табличные части, даже если вам нужен только номер и одна строка.
  3. Блокировки: Нагрузка на сервер растет пропорционально количеству документов.

Решение: Всегда старайтесь выгружать данные в один РезультатЗапроса. Если документ содержит несколько табличных частей, вы можете использовать несколько запросов в одном пакете или временные таблицы.

Технические нюансы сериализации

Рассмотрим несколько важных моментов, которые помогут сделать ваш JSON корректным:

Обработка больших объемов данных

Если вам нужно выплюнуть (как выразился автор темы) сотни тысяч документов, создание одного огромного Массива в памяти приведет к ошибке Нехватка памяти. В этом случае выясним правильный алгоритм работы:

  1. Открываем файл через ЗаписьJSON.ОткрытьФайл().
  2. Записываем начало массива [.
  3. В цикле обхода выборки запроса создаем структуру только для одного документа.
  4. Сразу записываем эту структуру в файл командой ЗаписатьJSON(ЗаписьJSON, СтруктураОдногоДокумента).
  5. Очищаем структуру (просто перезаписывая переменную) и переходим к следующему документу.
  6. Записываем конец массива ] и закрываем файл.

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

Итоги

Мы проанализировали ситуацию с выгрузкой массива документов и выяснили, что наиболее эффективным методом является сочетание грамотного запроса (с вложенными табличными частями) и формирования массива структур. Если же требуется полная копия объектов 1С, на помощь приходит СериализаторXDTO, но только при условии ручного управления границами массива в потоке JSON. Используйте эти подходы, чтобы ваши интеграции работали быстро и без ошибок.

← На главную