composer require lapaliv/laravel-bulk-upsert
Bulkable trait to your Eloquent model:
use Lapaliv\BulkUpsert\Bulkable;
class User extends Model {
use Bulkable;
}
$data = [
['email' => '[email protected]', 'name' => 'John'],
['email' => '[email protected]', 'name' => 'David'],
];
User::query()->bulk()->uniqueBy('email')->create($data);
$data = [
['email' => '[email protected]', 'name' => 'Jacob'],
['id' => 1, 'email' => '[email protected]', 'name' => 'Oscar'],
];
$users = User::query()->bulk()->uniqueBy(['email'])->upsertAndReturn($data);
$bulk = User::query()->bulk()->uniqueBy('email')->chunk(100);
foreach ($data as $item) {
$bulk->createOrAccumulate($item);
}
$bulk->createAccumulated();
User::query()
->whereIn('id', [1, 2, 3, 4])
->selectAndUpdateMany(['role' => null]);
User::query()->bulk()
->onCreating(fn(User $user) => {
// Pre-create logic
})
->onCreated(fn(User $user) => {
// Post-create logic
})
->upsert($data);
$bulk = User::query()->bulk()->chunk(50);
foreach ($data as $item) {
$bulk->upsertOrAccumulate($item);
}
// Flush remaining items
$bulk->upsertAccumulated();
// app/Observers/UserObserver.php
public function creatingMany(Collection $users, BulkRows $bulkRows) {
$bulkRows->each(fn(BulkRow $row) => {
// Custom logic per row
});
}
// Handle bulk payloads from API
$bulk = User::query()->bulk()->uniqueBy('email');
$bulk->onCreatingMany(fn(Collection $users) => {
$this->validateBulkData($users);
});
$bulk->upsert($request->input('users'));
DB::transaction(function () use ($bulk, $data) {
$bulk->upsert($data);
// Additional transactional operations
});
Unique Key Mismatch
uniqueBy() matches the actual unique constraint in your database.uniqueBy(['email', 'status']) must align with a composite unique index.Event Order Confusion
onSaving fires before onCreating/onUpdating. Return false to skip operations.->onSaving(fn(User $user) => {
if ($user->email === '[email protected]') {
return false; // Skip this record
}
})
Chunk Size Too Small
chunk(1)) defeat the purpose of bulk operations.chunk(100) or higher for optimal performance.Missing Fillable Fields
$data are in $fillable or use massAssign:
protected $fillable = ['email', 'name', 'custom_field'];
Observer Conflicts
creating and onCreating).Log BulkRows
->onCreatingMany(fn(Collection $users, BulkRows $bulkRows) => {
\Log::debug($bulkRows->toArray());
})
Check SQL Queries
DB::enableQueryLog();
$bulk->upsert($data);
\Log::debug(DB::getQueryLog());
Validate Data Before Bulk Operations
->onSavingMany(fn(Collection $users, BulkRows $bulkRows) => {
$bulkRows->reject(fn(BulkRow $row) => !valid($row->original));
})
Custom BulkRow Processing
Lapaliv\BulkUpsert\Entities\BulkRow for additional metadata:
class CustomBulkRow extends BulkRow {
public function getExtraData() { ... }
}
Dynamic Unique Keys
uniqueBy:
->uniqueBy(fn(BulkRow $row) => [$row->original['email'], $row->original['tenant_id']])
Bulk Soft Deletes with Conditions
->onDeletingMany(fn(Collection $users, BulkRows $bulkRows) => {
$bulkRows->filter(fn(BulkRow $row) => $row->model->isActive);
})
Post-Upsert Hooks
onSavedMany to trigger side effects (e.g., webhooks, notifications):
->onSavedMany(fn(Collection $users) => {
Notification::send($users, new UserCreated());
})
chunk(N) explicitly.*Many) fire after single-model events.Illuminate\Database\Eloquent\SoftDeletes trait on the model.How can I help you explore Laravel packages today?