# Массовая обработка

## Описание раздела

Скрипты и шаблоны для обработки больших объёмов данных в JEXL. Используются при миграции, пересчёте, восстановлении или массовом обновлении записей. Содержат примеры работы с `ElExpOQuery`, `Btk_BulkProcessPkg` и передачи Scala-объектов через `MODULE$`.

## Скрипты

### Шаблон массовой обработки через ElExpOQuery

Используется как основа для написания производительных JEXL-скриптов, обрабатывающих тысячи записей. Демонстрирует использование объектного запроса `ElExpOQuery` для пакетной загрузки сущностей и обработки по чанкам.

Место применения: `Сервис > Инструменты > Выполнить JEXL-скрипт`

```{attention} 
Требует адаптации под конкретную сущность и версию системы. Перед использованием убедитесь, что целевой API (например, `Co_ProdCostDocEntryApi`) и соответствующие Scala-объекты доступны в вашей версии платформы.
```

Тип: JEXL-скрипт

```scala
const vDocApi = Co_ProdCostDocEntryApi;

const mkDocOQuery = (idap) => {
  const vOQ = new ru.bitec.app.gtk.eclipse.query.ElExpOQuery(vDocApi);
  const idavAL = new java.util.ArrayList();
  idap.foreach(idv => idavAL.add(idv));

  vOQ.forWhere(vBuilder => vBuilder.get("id").in(idavAL.toArray()) );
  vOQ.batchIn(
    asScala([session.sbtClassLoader().loadClass("ru.bitec.app.co.prodcostdocentry.Co_ProdCostDocEntryDetAta$").MODULE$, ...])
  );
  return vOQ;
};

asScala(sql(`
  select t.id
    from Co_ProdCostDocEntry t
   where t.dDoc is not null
     and t.idStateMC >= 300
`).asList()).grouped(400).foreach(ravBatch => {
  mkDocOQuery(ravBatch.map(r => r.id)).foreach(ropDoc => {
    Co_ProdCostRegFullApi.createItemsByDoc(ropDoc, ropDoc.dDoc);
  });
  commit();
});
```

### Шаблон массовой обработки через Btk_BulkProcessPkg

Используется как основа для массовой обработки записей с автоматическим разбиением на чанки. Демонстрирует применение `Btk_BulkProcessPkg.chunkedQuery` для безопасной работы с большими выборками без переполнения памяти.

Место применения: `Сервис > Инструменты > Выполнить JEXL-скрипт`

```{attention} 
Требует адаптации под конкретную сущность и версию системы. Классы Scala-объектов (например, `Co_ProdCostDocEntryDetAta$`) могут отсутствовать или измениться в новых версиях платформы.
```

Тип: JEXL-скрипт

```scala
Btk_BulkProcessPkg.chunkedQuery(
  Co_ProdCostDocEntryApi,
  5000L,
  `select t.id from Co_ProdCostDocEntry t`,
  asScala([...]), // Неизвестен способ передачи NamedParameter из JEXL
  asScala([session.sbtClassLoader().loadClass("ru.bitec.app.co.prodcostdocentry.Co_ProdCostDocEntryDetAta$").MODULE$, ...]),
  false,
  false,
  ropa => {
    ropa.foreach(rop => Btk_InfoLogPkg.info(rop.gid));
  }
);
```

### Обработка данных пакетами

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

Скрипт показывает подход для массового изменения большого объема данных, когда обработка всех записей за один проход может привести к переполнению памяти и остановке веб-приложения. Записи выбираются и обрабатываются пачками. После обработки каждой пачки выполняется `commit()`, затем запрашивается следующая часть данных.

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

Место применения: `Сервис > Инструменты > Выполнить JEXL-скрипт`

Тип: JEXL-скрипт

<!-- Начало кода -->
```java
// Обработка данных по пачкам
var batchSize = 200;
var nCount = 0;
var nOffset = 0;

var sqlText = `
<запрос>
`;

while (true) {
  // offset не нужен, если после каждой пачки отдается commit в БД
  // и запрос исключает уже обработанные записи
  var listSQL = sql(sqlText + " offset " + nOffset + " limit " + batchSize).asList();
  
  // Условие выхода из цикла
  if (listSQL.isEmpty()) {
    break;
  }
  
  for (data : listSQL) {
    var ropPlacement = Bs_PlacementApi.load(data.id);
    Bs_PlacementApi.setObjAttrValue(ropPlacement, "idMonitorTrainLocationType", data.idtype);
    nCount += 1;
  }
  
  commit();
  nOffset += batchSize;
}

// Результат
if (nCount == 0) {
  dialogs.showMessage("Исправлять нечего.");
} else {
  dialogs.showMessage("Исправлено " + nCount + " записей.");
}
```
<!-- Конец кода -->