Insert or update hundreds of database rows in a single SQL query using Eloquent's batch upsert() method.
When synchronizing large catalogs, importing CSV files, or updating product inventory in bulk, executing individual updateOrCreate() calls inside a loop executes hundreds of separate database roundtrips.
Laravel provides the upsert() method to compile batch inserts and updates into a single SQL statement.
Bulk Upserting Records
use App\Models\Product;
Product::upsert(
// 1. Array of records to insert or update
[
['sku' => 'PROD-001', 'name' => 'Keyboard', 'price' => 79.99, 'stock' => 15],
['sku' => 'PROD-002', 'name' => 'Mouse', 'price' => 49.99, 'stock' => 30],
['sku' => 'PROD-003', 'name' => 'Monitor', 'price' => 299.99, 'stock' => 5],
],
// 2. Unique column(s) that identify an existing row
['sku'],
// 3. Columns that should be updated if a matching row exists
['price', 'stock']
);
How It Works
- If the
skudoes not exist, the record is inserted. - If the
skumatches an existing row, onlypriceandstockare updated; thenamecolumn remains untouched. - Executes as a single
INSERT INTO ... ON DUPLICATE KEY UPDATE(MySQL) orON CONFLICT ... DO UPDATE(PostgreSQL).
Summary
- Reduces hundreds of database queries into a single batch execution.
- Second argument specifies the unique/primary key column(s).
- Third argument specifies the exact attributes to update on collision.
Related Tips
View all tips →Optimize Date Queries by Replacing whereYear() with whereBetween()
Replace whereYear() and whereMonth() on large database tables with whereBetween() date ranges to enable SQL index lookups.
Sort Eloquent Results by Subquery Columns with orderByDesc()
Use query builder subqueries inside orderBy() and orderByDesc() to sort models by aggregated or related table columns directly in SQL.