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