---
title: "chunkById() - безпечна пакетна обробка"
url: https://laravelukraine.com/blog/chunkbyid-bezpecna-paketna-obrobka
author: "Олексій Бабінцев"
date: 2026-08-03
---

# chunkById() - безпечна пакетна обробка

Обробляєте таблицю через `chunk()` і одночасно змінюєте колонку, за якою фільтруєте? Частина записів буде пропущена.

`chunk()` гортає сторінки через OFFSET. Якщо запис випадає з вибірки під час обробки, решта зсувається - і цілий пакет ви не побачите.

**Як працює chunkById():**

Замість OFFSET використовує `where('id', '>', $lastId)`. Зсув вибірки більше не ламає ітерацію.

**Коли обов'язково chunkById():**

* Оновлюєте поле, за яким фільтруєте
* Видаляєте записи під час обходу
* Будь-яка міграція даних із записом у ту саму таблицю

Порада: сортування задає сам `chunkById()` - не додавайте власний `orderBy()`, він його перезапише.

```php
// НЕБЕЗПЕЧНО: пропустить половину записів
User::where('notified', false)
  ->chunk(100, function ($users) {
    foreach ($users as $user) {
      $user->update(['notified' => true]);
      // Вибірка "з'їдається", OFFSET перестрибує записи
    }
  });

// БЕЗПЕЧНО: курсор по первинному ключу
User::where('notified', false)
  ->chunkById(100, function ($users) {
    foreach ($users as $user) {
      $user->update(['notified' => true]);
    }
  });
```

```php
// Видалення під час обходу - тільки chunkById()
Log::where('created_at', '<', now()->subYear())
  ->chunkById(500, function ($logs) {
    $logs->each->delete();
  });

// Власна колонка-курсор (наприклад, UUID-таблиця)
Order::where('status', 'pending')
  ->chunkById(200, function ($orders) {
    $orders->each->process();
  }, column: 'uuid');

// Читання без змін - звичайний chunk() достатній
Product::chunk(1000, function ($products) {
  foreach ($products as $product) {
    $this->exportToCsv($product);
  }
});

// each() - те саме, але по одному запису
User::where('active', true)->eachById(function ($user) {
  $user->recalculateStats();
}, 200);
```
