Работа с массивами объектов в 1С:Предприятие 8.3 — одна из самых востребованных задач при разработке конфигураций, отчетов и обработок.hether вы только начинаете осваивать платформу или уже опытный программист, умение эффективно получать collections объектов сэкономит часы работы и убережет от типичных ошибок. В этой статье мы разберем все актуальные способы: от элементарного перебора справочников до сложных запросов с joins и группировками.

Особое внимание уделим производительности каждого метода — этот аспект часто упускают, хотя от него зависит скорость работы ваших решений на больших базах. Например, выборка 10 000 документов через ПолучитьСписок() и через запрос может отличаться по времени в десятки раз. Мы также рассмотрим нюансы работы с управляемыми формами, обычными формами и серверными процедурами, где подходы к получению данных принципиально разные.

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

1. Базовые методы: Получение массива через коллекции объектов

Начнем с самого простого — работы со встроенными коллекциями платформы. Этот способ подходит для небольших объемов данных (до 1 000–2 000 объектов), когда не требуется сложная фильтрация или сортировка.

Основные методы, которые вам пригодятся:

  • 📋 Справочник.Номенклатура.ПолучитьСписок() — возвращает массив всех элементов справочника без фильтров. Внимание: на больших справочниках вызовет зависание!
  • 🔍 Документ.РеализацияТоваровУслуг.Выбрать() — создает выборку документов с возможностью фильтрации по дате, контрагенту и другим реквизитам.
  • 📊 Массив = Новый Массив; + Массив.Добавить(Объект) — ручное формирование массива в цикле. Полезно, когда нужно отобрать объекты по сложным условиям.
  • 🔄 Объект.ПолучитьОбъекты() — альтернатива ПолучитьСписок() для некоторых типов объектов (например, планы видов характеристик).

Пример кода для получения всех активных номенклатурных позиций:

МассивНоменклатуры = Справочник.Номенклатура.ПолучитьСписок();

Для Каждого Элемент Из МассивНоменклатуры Цикл

Если НЕ Элемент.ПометкаУдаления Тогда

АктивныеПозиции.Добавить(Элемент);

КонецЕсли;

КонецЦикла;

⚠️ Внимание: Метод ПолучитьСписок() загружает все реквизиты объектов в память, что может привести к переполнению на больших базах. Для выборки только нужных полей используйте Выбрать() с указанием отбираемых реквизитов.
💡

Если вам нужны только ссылки на объекты (без данных), используйте конструкцию Справочник.Номенклатура.ПолучитьСсылки() — это ускорит выполнение в 2–3 раза.

2. Запросы как универсальный инструмент

Язык запросов — самый мощный и гибкий способ получения массивов объектов. Он позволяет:

  • 🔗 Соединять данные из нескольких таблиц (ЛЕВОЕ СОЕДИНЕНИЕ, ВНУТРЕННЕЕ СОЕДИНЕНИЕ)
  • 📈 Агрегировать данные (СУММА, КОЛИЧЕСТВО, МАКСИМУМ)
  • 🔎 Фильтровать по сложным условиям (ГДЕ с вложенными запросами)
  • 📊 Сортировать и группировать результаты

Базовый шаблон запроса для получения массива документов:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| РеализацияТоваровУслуг.Ссылка КАК Ссылка,

| РеализацияТоваровУслуг.Дата КАК Дата,

| РеализацияТоваровУслуг.Контрагент КАК Контрагент

|ИЗ

| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

|ГДЕ

| РеализацияТоваровУслуг.Дата МЕЖДУ &НачалоПериода И &КонецПериода

|УПОРЯДОЧИТЬ ПО

| Дата УБЫВ";

Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(ТекущаяДата()));

Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(ТекущаяДата()));

РезультатЗапроса = Запрос.Выполнить();

МассивДокументов = РезультатЗапроса.Выгрузить();

Ключевые преимущества запросов:

ХарактеристикаКоллекции объектовЗапросы
Производительность на больших данныхНизкаяВысокая
Сложная фильтрацияТребует ручного кодаВстроенная поддержка
Объединение данных из нескольких источниковНевозможноЛегко реализуется
Агрегация (суммы, средние)Требует дополнительных цикловВстроенные функции
ПамятьЗагружает все реквизитыМожно выбрать только нужные поля
📊 Какой метод получения данных вы используете чаще?
Методы коллекций (ПолучитьСписок, Выбрать)
Запросы
Обход в цикле
Другое

3. Оптимизация производительности: что ускоряет, а что тормозит

Даже правильно написанный код может работать медленно, если не учитывать особенности платформы. Вот ключевые факторы, влияющие на скорость:

Что замедляет выполнение:

  • 🐢 Получение всех реквизитов вместо нужных: ПолучитьСписок() vs Выбрать(Реквизит1, Реквизит2)
  • 🔄 Вложенные циклы по большим коллекциям (например, перебор 10 000 документов с проверкой каждого товара)
  • 🗄️ Частые обращения к базе в цикле: лучше загрузить данные один раз в массив, а потом работать с ним.
  • 📉 Отсутствие индексов на полях, по которым идет фильтрация в запросах.

Как ускорить:

  • ⚡ Используйте ПОМЕСТИТЬ в запросах для временных таблиц с промежуточными результатами.
  • 📌 Применяйте ИНДЕКСИРОВАТЬ ПО для полей, по которым часто фильтруете данные.
  • 🔧 Разбивайте сложные запросы на несколько простых с использованием ОБЪЕДИНИТЬ.
  • 🖥️ Для серверных процедур используйте НаСервере — это уменьшает нагрузку на клиент.

Пример оптимизированного запроса с временной таблицей:

Запрос.Текст =

"ВЫБРАТЬ РАЗРЕШЕННЫЕ

| Товары.Ссылка КАК Ссылка

|ПОМЕСТИТЬ ВТТовары

|ИЗ

| Справочник.Номенклатура КАК Товары

|ГДЕ

| Товары.ЭтоГруппа = ЛОЖЬ

| И Товары.ПометкаУдаления = ЛОЖЬ;

|

|////////////////////////////////////////////////////////////

|ВЫБРАТЬ

| ВТТовары.Ссылка КАК Ссылка,

| ВТТовары.Артикул КАК Артикул

|ИЗ

| ВТТовары КАК ВТТовары";

⚠️ Внимание: Начиная с версии 8.3.20, платформа автоматически кэширует результаты некоторых запросов. Однако это не отменяет необходимости оптимизации — кэш сбрасывается при изменении данных или перезапуске сеанса.

☑️ Проверка оптимизации запроса

Выполнено: 0 / 4

4. Работа с динамическими списками и управляемыми формами

В управляемых формах (а также в обычных формах с динамическими списками) получение массива объектов имеет свои особенности. Здесь важно понимать разницу между:

  • 📜 Статическим массивом — данные загружаются один раз (например, при открытии формы).
  • 🔄 Динамическим списком — данные подгружаются порциями при прокрутке (ленивая загрузка).

Пример получения данных для динамического списка в управляемой форме:

Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 100

| Контрагенты.Ссылка КАК Ссылка,

| Контрагенты.Наименование КАК Наименование

|ИЗ

| Справочник.Контрагенты КАК Контрагенты

|УПОРЯДОЧИТЬ ПО

| Наименование";

Результат = Запрос.Выполнить();

ДинамическийСписок.ЗагрузитьДанные(Результат.Выгрузить());

КонецПроцедуры

Для работы с большими списками (более 1 000 строк) рекомендуется:

  1. Использовать постраничную загрузку (ВЫБРАТЬ ПЕРВЫЕ N + кнопка "Загрузить еще").
  2. Отключать автоматическое обновление списка при изменении данных (ДинамическийСписок.АвтоОбновление = Ложь).
  3. Применять серверный поиск вместо клиентского фильтра.
Как отладить медленный динамический список?

1. Включите профилировщик запросов в конфигураторе (Сервис → Профилировщик запросов). 2. Проверьте, не загружаются ли лишние реквизиты в выборке. 3. Убедитесь, что фильтрация происходит на сервере, а не на клиенте. 4. Для списков более 5 000 строк рассмотрите возможность использования отчетов с СКД вместо динамических списков.

5. Типичные ошибки и как их избежать

Даже опытные разработчики иногда сталкиваются с проблемами при работе с массивами объектов. Вот самые распространенные ошибки и способы их решения:

Ошибка 1: "Недостаточно памяти"

Причина: Попытка загрузить в массив все документы за 5 лет (например, 50 000 записей).

Решение:

  • 📅 Разбивайте выборку по периодам (месяц/квартал).
  • 🗃️ Используйте ВыгрузитьДанные() с ограничением по количеству строк.
  • 🔧 Перепишите логику на использование ПостроительОтчета вместо массива.

Ошибка 2: "Объект не найден" при работе с ссылками

Причина: В массиве хранятся ссылки на объекты, которые были удалены или перенесены в архив.

Решение:

Для Каждого Ссылка Из МассивСсылок Цикл

Попытка

Объект = Ссылка.ПолучитьОбъект();

// Обработка объекта

Исключение

Сообщить("Объект не найден: " + Ссылка.Наименование);

КонецПопытки;

КонецЦикла;

Ошибка 3: Медленная сортировка массива

Причина: Сортировка массива из 10 000 элементов с использованием Массив.Сортировать() без указания метода сравнения.

Решение:

Процедура СравнитьЭлементы(Элемент1, Элемент2)

Возврат ?(Элемент1.Дата > Элемент2.Дата, 1, ?(Элемент1.Дата = Элемент2.Дата, 0, -1));

КонецПроцедуры

МассивДокументов.Сортировать(АдресПроцедуры("СравнитьЭлементы"));

⚠️ Внимание: При работе с распределенными информационными базами (РИБ) или обменами данными всегда проверяйте, что объекты в массиве принадлежат текущей базе. Использование ссылок из другой базы приведет к ошибке "Неверный формат данных".

6. Продвинутые техники: группировка, кэширование и асинхронность

Для сложных задач стандартных методов может быть недостаточно. Рассмотрим продвинутые подходы:

1. Группировка данных в запросе

Если вам нужно получить массив объектов с агрегированными данными (например, суммы продаж по контрагентам), используйте ГРУППИРОВКА ПО:

Запрос.Текст =

"ВЫБРАТЬ

| РеализацияТоваровУслуг.Контрагент КАК Контрагент,

| СУММА(РеализацияТоваровУслуг.СуммаДокумента) КАК ИтогоПродаж

|ИЗ

| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

|ГДЕ

| РеализацияТоваровУслуг.Дата МЕЖДУ &Начало И &Конец

|СГРУППИРОВАТЬ ПО

| РеализацияТоваровУслуг.Контрагент";

2. Кэширование результатов

Если один и тот же массив объектов запрашивается многократно (например, в отчете), сохраняйте его в МенеджерВременныхДанных:

Процедура ПолучитьКэшированныеДанные()

Если НЕ МенеджерВременныхДанных.Существует("МассивКонтрагентов") Тогда

Массив = ПолучитьМассивКонтрагентовИзБазы();

МенеджерВременныхДанных.Вставить("МассивКонтрагентов", Массив);

КонецЕсли;

Возврат МенеджерВременныхДанных.Получить("МассивКонтрагентов");

КонецПроцедуры

3. Асинхронная загрузка данных

Для управляемых форм можно использовать ПоказатьОповещениеПользователя() с фоновой загрузкой:

Процедура ЗагрузитьДанныеАсинхронно()

Оповещение = ПоказатьОповещениеПользователя("Идет загрузка данных...", 0);

АсинхроннаяПроцедура Загрузка()

МассивДанных = ДолгийЗапросКБазе();

Оповещение.Закрыть();

ЗаполнитьТаблицуДанными(МассивДанных);

КонецПроцедуры

Загрузка();

КонецПроцедуры

Эти техники особенно полезны для:

  • 📊 Отчетов с большим объемом данных.
  • 🖥️ Веб-сервисов и HTTP-сервисов, где важна скорость ответа.
  • 📱 Мобильных приложений на платформе 1С:Мобильная платформа.
💡

Кэширование и асинхронная загрузка могут сократить время ожидания пользователя в 5–10 раз, но требуют аккуратной реализации, чтобы избежать утечек памяти.

7. Альтернативные подходы: внешние источники и интеграции

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

1. Получение данных из другой базы 1С

Используйте COMСоединение или веб-сервисы:

Соединение = Новый COMОбъект("V83.COMConnector");

Подключение = Соединение.Connect("File=""C:\Bases\ExternalBase"";Usr=""Администратор"";");

Запрос = Подключение.NewObject("Запрос");

Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 100 Справочник.Контрагенты.Ссылка КАК Ссылка";

Результат = Запрос.Выполнить();

Массив = Результат.Выгрузить();

2. Импорт из Excel или JSON

Для загрузки данных из файлов:

// Чтение JSON

ЧтениеJSON = Новый ЧтениеJSON;

ЧтениеJSON.УстановитьСтроку(ПолучитьТекстИзФайла("data.json"));

МассивДанных = ПрочитатьJSON(ЧтениеJSON);

// Чтение Excel через OLE

Excel = Новый COMОбъект("Excel.Application");

Книга = Excel.Workbooks.Open("C:\data.xlsx");

Лист = Книга.Worksheets(1);

Данные = Лист.UsedRange.Value;

3. Работа с HTTP-сервисами

Пример получения данных из REST API:

HTTPСоединение = Новый HTTPСоединение("api.example.com", 80);

Запрос = Новый HTTPЗапрос("/v1/products");

Ответ = HTTPСоединение.Получить(Запрос);

МассивТоваров = JSON.Прочитать(Ответ.ПолучитьТекст());

⚠️ Внимание: При работе с внешними источниками всегда обрабатывайте исключения (ошибки сети, неверный формат данных, таймауты). Используйте Попытка...Исключение для предотвращения падения программы.

FAQ: Ответы на частые вопросы

Как получить массив объектов с отбором по нескольким условиям?

Используйте комбинацию методов Выбрать() с фильтрами или запрос с несколькими условиями в секции ГДЕ:

Выборка = Справочник.Номенклатура.Выбрать();

Пока Выборка.Следующий() Цикл

Если Выборка.Цена > 1000 И Выборка.Остаток > 0 Тогда

Массив.Добавить(Выборка.Ссылка);

КонецЕсли;

КонецЦикла;

Для сложных условий лучше использовать запрос с операторами И, ИЛИ, В().

Можно ли получить массив объектов из регистра накопления?

Да, но только через запрос. Пример для регистра ТоварыНаСкладах:

Запрос.Текст =

"ВЫБРАТЬ

| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,

| ТоварыНаСкладахОстатки.КоличествоОстаток КАК Остаток

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки";

Для виртуальных таблиц (Остатки, Обороты) обязательно указывайте период отбора.

Как экспортировать массив объектов в Excel?

Используйте Библиотеку стандартных подсистем (БСП) или COMОбъект("Excel.Application"):

Excel = Новый COMОбъект("Excel.Application");

Книга = Excel.Workbooks.Add();

Лист = Книга.Worksheets(1);

// Заполнение заголовков

Лист.Cells(1, 1).Value = "Наименование";

Лист.Cells(1, 2).Value = "Артикул";

// Заполнение данных

Для i = 0 По Массив.ВГраница() Цикл

Лист.Cells(i + 2, 1).Value = Массив[i].Наименование;

Лист.Cells(i + 2, 2).Value = Массив[i].Артикул;

КонецЦикла;

Книга.SaveAs("C:\Export.xlsx");

Excel.Quit();

Для больших массивов (>10 000 строк) лучше использовать ADODB.Stream для записи в CSV.

Почему запрос возвращает пустой массив, хотя данные есть?

Частые причины:

  1. Ошибка в условии отбора (например, неверный формат даты: Дата = '2023-12-31' вместо Дата = ДАТАВРЕМЯ(2023, 12, 31)).
  2. Отсутствуют права у пользователя на чтение данных.
  3. В запросе используются несуществующие поля или псевдонимы.
  4. Для регистров не указан период или неверно выбрана виртуальная таблица.

Включите отладку запроса (Запрос.Отладка = Истина;) для вывода исполняемого SQL-кода.

Как получить массив объектов с иерархией (дерево справочника)?

Используйте рекурсивный обход или запрос с ПУТЬ:

Процедура ПолучитьДерево(Родитель, Массив)

Выборка = Справочник.Номенклатура.Выбрать(Родитель);

Пока Выборка.Следующий() Цикл

Массив.Добавить(Выборка.Ссылка);

ПолучитьДерево(Выборка.Ссылка, Массив); // Рекурсия

КонецЦикла;

КонецПроцедуры

// Или через запрос:

Запрос.Текст =

"ВЫБРАТЬ

| Номенклатура.Ссылка КАК Ссылка,

| ПУТЬ(Номенклатура.Ссылка) КАК Путь

|ИЗ

| Справочник.Номенклатура КАК Номенклатура";