При интеграции 1С с внешними системами (веб-сайтами, мобильными приложениями или другими информационными базами) одной из самых частых задач является выгрузка данных в формате JSON. Если выгрузить один документ достаточно просто, то при работе с массивом документов, особенно имеющих сложные табличные части, начинающие разработчики часто сталкиваются с ошибками потоковой записи или низкой производительностью кода. В этой статье мы подробно разберем, как правильно организовать выгрузку коллекции документов, оптимизировать запросы и избежать типичных ошибок. В качестве альтернативы ручному программированию можно использовать визуальный конструктор API для настройки обмена данными в формате JSON.
Разберем ситуацию: вы пытаетесь использовать СериализаторXDTO.ЗаписатьJSON внутри цикла для каждого документа. При этом вы уже открыли объект ЗаписьJSON. Проблема заключается в том, что СериализаторXDTO при вызове метода записи пытается создать законченный JSON-узел. Если вы просто вызываете его в цикле, он «не понимает», что эти объекты должны быть частью одного массива. Чтобы JSON-файл был валидным, он должен иметь четкую структуру: либо один корневой объект, либо один корневой массив.
Проанализируем способы решения этой задачи — от простых до наиболее производительных.
Это самый гибкий и популярный метод. Мы подготавливаем данные в виде обычных коллекций 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.Закрыть();
КонецПроцедуры
В данном примере мы используем вложенную выборку в запросе. Это позволяет за один сеанс работы с базой данных получить и заголовки документов, и их строки, что гораздо быстрее, чем получать объект через ПолучитьОбъект() в цикле.
Если вам необходимо выгрузить объекты именно в формате XDTO (со служебными полями типа #type и #value), или документов слишком много, чтобы держать их все в памяти в виде массива структур, используйте потоковую запись. Выясним, как правильно организовать этот процесс, чтобы не получить ошибку порядка записи.
Ключевой момент — ручное управление началом и концом массива в ЗаписьJSON.
Процедура ВыгрузитьЧерезXDTO(МассивСсылок, ПутьКФайлу)
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.ОткрытьФайл(ПутьКФайлу);
// Явно указываем начало массива в JSON
ЗаписьJSON.ЗаписатьНачалоМассива();
Для Каждого Ссылка Из МассивСсылок Цикл
// Получаем объект документа (внимание: это создает нагрузку при больших объемах!)
ОбъектДокумента = Ссылка.ПолучитьОбъект();
// Сериализатор запишет один объект внутрь текущего массива
СериализаторXDTO.ЗаписатьJSON(ЗаписьJSON, ОбъектДокумента, НазначениеТипаXML.Явное);
КонецЦикла;
// Явно указываем конец массива
ЗаписьJSON.ЗаписатьКонецМассива();
ЗаписьJSON.Закрыть();
КонецПроцедуры
Важное замечание: Метод СериализаторXDTO.ЗаписатьJSON выгружает объект «как есть» согласно его схеме. Это означает, что в JSON попадут абсолютно все реквизиты и все табличные части документа. Если вам нужна только часть данных, лучше использовать Способ 1.
Одной из главных ошибок, упомянутых в обсуждении на форуме, является получение данных через «точку» (например, Выборка.Ссылка.Номер или Для Каждого Строка ИЗ Выборка.Ссылка.Товары). Проанализируем, почему это плохо:
Ссылка.Реквизит, система выполняет отдельный неявный запрос к базе данных.ПолучитьОбъект() 1С считывает из базы вообще все данные документа, включая все табличные части, даже если вам нужен только номер и одна строка.Решение: Всегда старайтесь выгружать данные в один РезультатЗапроса. Если документ содержит несколько табличных частей, вы можете использовать несколько запросов в одном пакете или временные таблицы.
Рассмотрим несколько важных моментов, которые помогут сделать ваш JSON корректным:
НастройкиСериализацииJSON, чтобы установить ВариантЗаписиДатыJSON.ISO. Это стандарт для большинства современных API.Строка(Ссылка.УникальныйИдентификатор()).Число (целое или дробное) так, как это делает 1С. Числа всегда записываются без кавычек, а строки — в кавычках.null или вообще исключать это поле из структуры.Если вам нужно выплюнуть (как выразился автор темы) сотни тысяч документов, создание одного огромного Массива в памяти приведет к ошибке Нехватка памяти. В этом случае выясним правильный алгоритм работы:
ЗаписьJSON.ОткрытьФайл().[.ЗаписатьJSON(ЗаписьJSON, СтруктураОдногоДокумента).] и закрываем файл.Такой потоковый подход позволяет обрабатывать гигабайты данных, используя всего несколько мегабайт оперативной памяти, так как данные не копятся в памяти, а порциями сбрасываются на жесткий диск.
Мы проанализировали ситуацию с выгрузкой массива документов и выяснили, что наиболее эффективным методом является сочетание грамотного запроса (с вложенными табличными частями) и формирования массива структур. Если же требуется полная копия объектов 1С, на помощь приходит СериализаторXDTO, но только при условии ручного управления границами массива в потоке JSON. Используйте эти подходы, чтобы ваши интеграции работали быстро и без ошибок.