Разработка и Конфигурация · 11 мин
Как перебрать все документы в 1С 8.3
Способы перебрать все документы в 1С 8.3: Выбрать(), запрос, выборка по периоду и организации. Примеры кода, ошибки, производительность и проверка результата.
Перебор всех документов определённого вида — одна из самых частых задач при доработке конфигураций 1С 8.3: перепроведение, заполнение нового реквизита, выгрузка данных, поиск ошибок в учёте. Платформа предлагает несколько способов обхода документов, и выбор конкретного влияет на скорость выполнения, потребление памяти и безопасность данных.
Основных подхода три: метод Выбрать() менеджера документа, запрос к таблице документа и прямой обход через объектные ссылки. Каждый имеет свои ограничения: первый прост, но медленно читает объекты целиком; запрос быстрее, но возвращает только поля, а не готовые объекты; ручной обход требует аккуратности с блокировками.
Ниже разобраны рабочие примеры кода для толстого и тонкого клиента, типичные ошибки начинающих разработчиков и способы ускорить обработку больших объёмов документов без риска повредить данные.
Базовый перебор через метод Выбрать()
Самый простой способ — метод Выбрать() у менеджера документа. Он возвращает выборку, которую можно обойти в цикле. Выборка содержит ссылки на документы, отсортированные по дате и номеру.
Выборка = Документы.РеализацияТоваровУслуг.Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить("Документ: " + Выборка.Ссылка);
КонецЦикла;
У метода есть параметры: Выбрать(НачалоПериода, КонецПериода, Отбор, Порядок). Ограничение периода резко сокращает объём выборки, поэтому всегда указывайте даты, если задача позволяет. Отбор задаётся структурой по индексированным реквизитам (организация, контрагент и т.п.).
Отбор = Новый Структура("Организация", ТекущаяОрганизация);
Выборка = Документы.РеализацияТоваровУслуг.Выбрать(
НачалоГода(ТекущаяДатаСеанса()),
КонецГода(ТекущаяДатаСеанса()),
Отбор);
Пока Выборка.Следующий() Цикл
// работа с Выборка.Ссылка
КонецЦикла;
Важно понимать: выборка возвращает ссылки и значения полей, доступных в списке документа, но не табличные части. Если нужно читать или менять табличную часть, придётся получать объект через Выборка.Ссылка.ПолучитьОбъект().
Перебор документов запросом
Запрос — предпочтительный способ, когда нужно отобрать документы по сложным условиям, соединить их с другими таблицами или просто получить список ссылок для отчёта. Запрос выполняется на сервере СУБД и работает заметно быстрее объектного обхода.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Реализация.Ссылка КАК Ссылка,
| Реализация.Номер КАК Номер,
| Реализация.Дата КАК Дата
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
| Реализация.Дата МЕЖДУ &Начало И &Конец
| И Реализация.Проведен";
Запрос.УстановитьПараметр("Начало", НачалоГода(ТекущаяДатаСеанса()));
Запрос.УстановитьПараметр("Конец", КонецГода(ТекущаяДатаСеанса()));
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Номер + " от " + Выборка.Дата);
КонецЦикла;
Для массовой обработки результат запроса удобно выгрузить в таблицу значений через Выгрузить() — тогда можно заранее посчитать количество документов и показывать пользователю прогресс выполнения.
Запрос не даёт доступа к табличным частям напрямую из основной таблицы документа: их выбирают отдельным запросом к таблице вида Документ.ИмяДокумента.ИмяТабличнойЧасти с условием по ссылке. Для обхода всех табличных частей всех документов это рациональнее делать одним соединением, а не запросом в цикле.
Сравнение подходов
Простой код, отбор только по индексированным реквизитам. Подходит для небольших выборок и разовых обработок.
Гибкие условия, соединения, высокая скорость. Подходит для больших объёмов и отчётных задач, но не возвращает готовые объекты.
Быстрый отбор нужных документов, объекты читаются только у тех, что требуют изменения. Оптимален для массового перепроведения и заполнения реквизитов.
Как изменить документы в цикле безопасно
Если задача — не просто прочитать, а изменить документы (заполнить реквизит, перепровести), то внутри цикла нужно получить объект, внести изменения и записать. Типовой шаблон выглядит так:
Пока Выборка.Следующий() Цикл
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
ДокОбъект.Комментарий = "Обработан пакетно";
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
КонецЦикла;
Режим записи выбирайте осознанно. РежимЗаписиДокумента.Запись сохраняет документ без проведения, Проведение — проводит и формирует движения, ОтменаПроведения — снимает с проведения. Массовое проведение может изменить регистры и повлиять на отчётность, поэтому сначала проверяйте алгоритм на копии базы или на нескольких документах.
При ошибке записи одного документа цикл не должен прерываться молча. Оборачивайте запись в попытку-исключение и собирайте список проблемных ссылок:
Ошибки = Новый Массив;
Пока Выборка.Следующий() Цикл
Попытка
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
ДокОбъект.Записать(РежимЗаписиДокумента.Проведение);
Исключение
Ошибки.Добавить(Выборка.Ссылка);
КонецПопытки;
КонецЦикла;
Ускорение обхода больших объёмов
На базах с сотнями тысяч документов наивный цикл с ПолучитьОбъект() может работать часами. Основные приёмы ускорения: фильтровать на уровне запроса, а не в коде; получать объекты только для документов, которые реально меняются; избегать запросов внутри цикла.
Если внутри цикла нужны данные других таблиц (остатки, цены, реквизиты контрагентов), выберите их одним пакетным запросом до начала обхода и соедините с документами. Запрос в цикле — классическая причина десятикратного падения производительности.
Для очень больших обработок полезно разбивать работу на порции: обрабатывать документы помесячно или пакетами по несколько тысяч с записью прогресса. Так проще контролировать выполнение и безопасно перезапускать обработку после сбоя, не трогая уже обработанные документы.
- 1Сделайте резервную копию базы или убедитесь, что есть свежая выгрузка
- 2Напишите запрос, отбирающий только нужные документы, и проверьте количество строк
- 3Протестируйте обработку на 3–5 документах в копии базы
- 4Запустите полный обход с логированием ошибок и прогресса
- 5Проверьте результат: количество обработанных, список ошибок, контрольные отчёты
Особенности клиент-серверного режима и управляемых форм
В управляемом приложении код обхода документов должен выполняться на сервере: выборки и запросы недоступны в клиентском контексте. Обработку оформляют в серверной процедуре модуля объекта обработки или в общем серверном модуле, а с клиента передают только параметры (период, организацию, вид документа).
Длительные операции в пользовательском интерфейсе блокируют сеанс. Для массовых обходов в типовых конфигурациях используют механизм длительных операций (фоновые задания через БСП) или просто Задание = ФоновыеЗадания.Выполнить(...) в собственных разработках. Это позволяет пользователю продолжать работу и получать сообщения о прогрессе через обмен сообщениями фонового задания.
Учтите, что в серверном контексте недоступны интерактивные вызовы (Вопрос, Предупреждение, открытие форм). Все решения должны приниматься до запуска обхода, а результаты возвращаться структурой или таблицей значений.
Если обработка должна периодически обходить документы по расписанию, оформите её как регламентное задание с параметром «последняя обработанная дата». Так каждый запуск будет перебирать только новые документы, а не всю таблицу заново.
Типичные ошибки при переборе документов
Первая распространённая ошибка — обращение к объекту вместо ссылки без необходимости. Конструкция Выборка.Ссылка.Номер в цикле на каждой итерации фактически читает объект из базы. Если номер нужен в выборке, добавьте поле в запрос или используйте реквизиты выборки напрямую.
Вторая ошибка — изменение данных внутри обхода той же таблицы без учёта порядка. Запись документа может менять его позицию в выборке (например, при изменении даты), что приводит к пропуску или повторной обработке документов. Надёжнее сначала выгрузить ссылки в таблицу значений, а потом обходить её.
Третья группа ошибок связана с правами и блокировками. Под пользователем без прав на изменение части документов запись будет падать. В многопользовательском режиме длительный обход с записью может вызывать конфликты блокировок — снижайте размер транзакций и не держите открытой транзакцию на весь цикл.
Как проверить результат обработки
После завершения обхода сопоставьте количество отобранных документов с количеством успешно обработанных и списком ошибок — сумма должна сходиться. Расхождение означает, что часть документов потерялась, и нужно искать причину в логике цикла.
Для обработок, меняющих проведение или движения, сверьте контрольные итоги до и после: обороты по регистрам, сальдо по ключевым счетам, итоги типовых отчётов за период. Любое неожиданное изменение — повод откатиться на копию и разобраться в алгоритме.
Как проверить результат
Отобрано = обработано + ошибки
Часть документов не вошла ни в один список
Итоги регистров изменились только ожидаемым образом
Появились лишние или пропали нужные записи
Список пуст или содержит понятные причины по конкретным документам
Массовые одинаковые ошибки — признак ошибки в коде
Частые вопросы
Как перебрать документы всех видов сразу?
Используйте метаданные: цикл по Метаданные.Документы, внутри — Документы[Вид.Имя].Выбрать() по каждому виду. Учтите, что структура реквизитов у видов разная, поэтому обращаться к полям нужно через метаданные или только к общим свойствам (Ссылка, Дата, Номер, Проведен).
Как перебрать только проведённые документы?
В запросе добавьте условие ГДЕ Документ.Проведен. Метод Выбрать() не поддерживает отбор по признаку проведения напрямую, поэтому проверку Если Выборка.Проведен Тогда придётся делать внутри цикла, что медленнее запроса.
Почему цикл по выборке работает очень долго?
Чаще всего внутри цикла вызывается ПолучитьОбъект() для каждого документа или выполняются запросы. Замените чтение объектов на выбор полей в запросе, а запросы вынесите за пределы цикла, соединив данные заранее.
Можно ли прервать обход и продолжить с того же места?
Да, если перед обходом выгрузить ссылки в таблицу значений и сохранять индекс или последнюю обработанную ссылку (например, в хранилище общих настроек или константе). При повторном запуске обход начинается с сохранённой позиции.
Как перебрать строки табличной части всех документов?
Одним запросом к таблице Документ.ИмяДокумента.ИмяТабличнойЧасти с соединением к шапке по ссылке. Так вы получите все строки всех документов за один запрос вместо чтения каждого объекта целиком.
Опасно ли массовое перепроведение документов?
Да, если выполнять его без подготовки: перепроведение меняет движения по регистрам и может изменить отчётность. Обязательно сделайте копию базы, протестируйте на малой выборке и сверьте контрольные итоги до и после обработки.
Что важно запомнить
Для перебора документов в 1С 8.3 используйте Выбрать() для простых задач и запрос — для больших объёмов и сложных отборов. Объекты получайте только у документов, которые нужно изменить, ошибки собирайте через Попытка/Исключение, а перед массовой записью в рабочей базе всегда делайте копию и тестируйте на малой выборке.