Quick Summary
Laravel’s updateOrCreate method elegantly solves the common “update or insert” database dilemma. This Eloquent feature checks for an existing record using specified attributes; if found, it updates the record, otherwise it creates a new one. This single, atomic operation ensures data integrity, eliminates duplicate entries, and simplifies your code by replacing cumbersome conditional logic.
Table of Contents
For any website or application with customers on board, whether it’s eCommerce or just a simple portal, managing records is a critical task. This task would involve inserting new entries as well as updating existing ones. Handling it manually may introduce complexity and the risk of duplicate data.
Laravel updateOrCreate resolves this by consolidating both actions into a single, atomic operation. This Eloquent method efficiently ensures database integrity. It first attempts to update a matching record or then creates a new one if it doesn’t exist.
This blog covers Laravel updateOrCreate, its purpose, how it works, and how it differs from firstOrCreate. Let’s get straight into it.
What is updateOrCreate in Laravel?
updateOrCreate is an Eloquent method that provides a single, atomic operation. You can use it to update an existing database record or create a new one if it doesn’t exist. It eliminates the need for manual checks (find, where, etc.) to make your code more concise and prevent duplicate entries.
The method accepts two arrays of data:
- First Array ($attributes): The “search” criteria. Laravel uses these column-value pairs to find an existing record.
- Second Array ($values): The attributes to update or set on the new record.
How It Works
The logic is simple: “Find a record matching these attributes. If found, update it with these values. If not found, create a new record with a combination of both attributes and values.”
Practical Example
Imagine you have a users table and you want to update a user’s last login date, or create their record if they are a new user.
$user = User::updateOrCreate(
// Attributes to find the user by
[
'email' => 'john.doe@example.com'
],
// Values to update or set
[
'name' => 'John Doe',
'last_login_at' => now()
]
);
In this scenario, Laravel executes the following logic:
- Search: Looks for a User where email = ‘john.doe@example.com’.
- Found: If a user exists, it will update that record, setting the last_login_at to the current timestamp. The name will also be updated to ensure it’s consistent.
- Not Found: If no user exists with that email, it will create a new user with the email, name, and last_login_at all populated.
Purpose of updateOrCreate
Laravel’s updateOrCreate method is to eliminate a common, repetitive pattern in database operations: Check if a record exists to decide whether to update it or create a new one.
Before this method, developers would write code like this:
$user = User::where('email', 'john@example.com')->first();
if ($user) {
$user->update(['last_login' => now()]);
} else {
$user = User::create([
'email' => 'john@example.com',
'last_login' => now()
]);
}
updateOrCreate consolidates this entire process into a single, atomic, and more reliable operation. Its core purposes are code simplicity, data integrity, and developer efficiency, and to prevent duplicates.
In essence, updateOrCreate is a developer-friendly safeguard for data integrity. It streamlines the common “update or insert” workflow.
How Does Laravel updateOrCreate Work?
First and foremost, you need to know how the syntax of Laravel updateOrCreate works.
Model::updateOrCreate(
array $attributes,
array $values = []
);
$attributes (Array)
This is the condition array used to find the record. It typically includes the columns and their values that you want to use to search for an existing record in the database. If a record with these attributes is found, it will be updated.
Example:
User::updateOrCreate(
['email' => 'john@example.com'], // Conditions to find the existing record
);
Explanation: This will search for a record where the email column matches john@example.com.
$values (Array, Optional)
This array contains the data to be updated if the record is found. If no record is found, this data will be used to create a new record.
Example:
User::updateOrCreate(
['email' => 'john@example.com'], // Conditions to find the existing record
['name' => 'John Doe', 'age' => 30] // Values to update or create
);
Explanation: If the record is found, these fields will be updated. If no record is found, a new record will be created with these values.
Basic Example
In this example, we demonstrate how to use updateOrCreate to either update an existing record based on a single condition or create a new record if it doesn’t exist. This is particularly useful for operations like updating user information based on their email address.
// Update existing user or create a new one if it doesn't exist
User::updateOrCreate(
['email' => 'john@example.com'], // Condition to find the user
['name' => 'John Doe', 'age' => 30] // Data to update or insert
);
This will check if a user with the email john@example.com exists. If found, the user’s name and age will be updated. If not found, a new user will be created with the provided name and age.
Multiple Conditions
In cases where you need to match multiple criteria before deciding whether to update or create a record, updateOrCreate supports this by allowing you to pass an array of conditions. The following example demonstrates how to update or insert a product based on both SKU and category_id.
// Update or create a record based on multiple conditions
Product::updateOrCreate(
['sku' => 'ABC123', 'category_id' => 1], // Multiple conditions to find the product
['name' => 'New Product Name', 'price' => 99.99] // Data to update or insert
);
This will search for a product with both SKU equal to ABC123 and category_id equal to 1. If such a product exists, its name and price will be updated. If not, a new product will be created with the given attributes.
Understanding this syntax with examples helps you utilize updateOrCreate to handle common CRUD operations efficiently. Although implementing real-world queries can be complex, it’s recommended you to hire Laravel developers for building live projects.
Examples of Using updateOrCreate in Laravel
Here are various ways to use Laravel’s updateOrCreate method to efficiently manage data in your applications:
Creating or Updating a User Based on Email
In this example, we will create a new user with the specified attributes if an email doesn’t exist. If a user with that email already exists, it will be updated with the provided values.
use App\Models\User;
$user = User::updateOrCreate(
['email' => 'john@example.com'],
[
'name' => 'John Doe',
'password' => bcrypt('secret'),
]
);
Code Explanation:
- User::updateOrCreate: This line calls the updateOrCreate method on the User model.
- [’email’ => ‘john@example.com’]: This array specifies the unique identifier (email) to search for.
- [‘name’ => ‘John Doe’, ‘password’ => bcrypt(‘secret’)]: This array contains the values to update or create the user with. If a user with the specified email exists, these values will be updated. Otherwise, a new user will be created with these values.
This example demonstrates how to use updateOrCreate to efficiently create or update a user profile based on their email address.
Updating a Product’s Quantity
Here, we will update the quantity of the product with IDs 1 to 10. If the product doesn’t exist, it will create a new one with the specified ID and quantity.
use App\Models\Product;
$product = Product::updateOrCreate(
['id' => 1],
['quantity' => 10]
);
Code Explanation:
- Product::updateOrCreate: This line calls the updateOrCreate method on the Product model.
- [‘id’ => 1]: This array specifies the unique identifier (ID) to search for.
- [‘quantity’ => 10]: This array contains the value to update the product’s quantity with.
This example shows how to update the quantity of a product using updateOrCreate. Efficiently filter and upsert records using Laravel Eloquent WHEREIN in conjunction with batch input arrays.
Handling Form Submissions
In this example, the code will create or update an order for a logged-in user based on the form submission data.
use App\Models\Order;
$order = Order::updateOrCreate(
['user_id' => auth()->user()->id],
[
'total' => $request->input('total'),
'status' => 'pending',
]
);
Code Explanation:
- Order::updateOrCreate: This line calls the updateOrCreate method on the Order model.
- [‘user_id’ => auth()->user()->id]: This array specifies the unique identifier (user ID) to search for. The auth()->user()->id part gets the ID of the currently authenticated user.
- [‘total’ => $request->input(‘total’), ‘status’ => ‘pending’]: This array contains the values to update or create the order with based on the form submission data.
This example illustrates how to use updateOrCreate to create or update an order based on form submission data, making it easier to handle user interactions.
Implementing Caching
This example caches the result of the updateOrCreate operation for 60 seconds. If the user already exists in the cache, it will be returned without making a database query.
use Illuminate\Support\Facades\Cache;
use App\Models\User;
$user = Cache::remember('user_1', 60, function () {
return User::updateOrCreate(
['id' => 1],
['name' => 'John Doe']
);
});
Code Explanation:
- Cache::remember: This line caches the result of the updateOrCreate operation for 60 seconds.
- ‘user_1’: This is the cache key used to store the result.
- 60: This is the cache expiration time in minutes.
- function () { … }: This closure is executed if the cache doesn’t contain the result. It calls updateOrCreate to fetch or create the user data.
This example demonstrates how to combine updateOrCreate with caching to improve performance by avoiding unnecessary database queries. Speed up batch record management by pairing Laravel Simple Pagination with updateOrCreate for smooth updates in large datasets.
Customizing Update Logic
In this example, we will use a closure to customize the update logic. Here, the quantity of the product will be incremented by 5.
use App\Models\Product;
$product = Product::updateOrCreate(
['id' => 1],
function ($product) {
$product->quantity += 5;
return $product;
}
);
Code Explanation:
- Product::updateOrCreate: This line calls the updateOrCreate method on the Product model.
- [‘id’ => 1]: This array specifies the unique identifier (ID) to search for.
- function ($product) { … }: This closure is executed if a product with the specified ID exists. It increments the product’s quantity by 5 and returns the updated product.
This example shows how to customize the update logic within updateOrCreate using a closure.
updateOrCreate Vs firstOrCreate: Key Differences
Both updateOrCreate and firstOrCreate are powerful Laravel Eloquent techniques for efficient data management. However, they serve slightly different purposes.
| Feature | updateOrCreate | firstOrCreate |
|---|---|---|
| Purpose | Finds a record, updates it if found, or creates a new one if it doesn’t exist. | Finds a record or creates a new one if it doesn’t exist. |
| Return Value | Updated or created model instance. | Model instance (always). |
| Update Logic | Customizable using a closure. | Not customizable. |
| Behavior | Updates existing record if found, creates new one if not. | Retrieves existing record if found, creates new one if not. |
| Use Case | When you want to create or update a record based on specific conditions and potentially modify its values. | When you primarily want to retrieve an existing record, but are willing to create a new one if it doesn’t exist. |
| Number of Queries | Typically 1 query for search, 1 for creation if needed | Typically 1 or 2 queries (search and update/create) |
The core distinction lies in their behavior when a matching record is found.
Code for Using updateOrCreate
use App\Models\User;
$user = User::updateOrCreate(
['email' => 'john@example.com'],
[
'name' => 'John Doe',
'password' => bcrypt('secret'),
]
);
updateOrCreate: Update if Found
When using updateOrCreate, Laravel looks for a user with the email ‘john@example.com’.
- If FOUND: It will update that existing record’s name and password with the new values from the second array.
- If NOT FOUND: It will create a new user with the combined attributes from both arrays.
This method is for when you want to synchronize data, ensuring a record has the latest information.
Code for Using firstOrCreate
use App\Models\User;
$user = User::firstOrCreate(
['email' => 'jane@example.com'],
[
'name' => 'Jane Doe',
'password' => bcrypt('secret'),
]
);
firstOrCreate: Ignore if Found
When using firstOrCreate, Laravel looks for a user with the email ‘jane@example.com’.
- If FOUND: It simply returns that existing record. The name and password in the second array are ignored completely.
- If NOT FOUND: It will create a new user with the combined attributes from both arrays.
This method is for when you want to retrieve an existing record or, only as a fallback, create it with initial data. It will not modify existing records.
By understanding these two Eloquent techniques and many more, you will be able to build an optimized Laravel site. But if you are struggling to leverage these technicalities for your program, consult with a dedicated Laravel development company.
Best Practices for Using updateOrCreate
updateOrCreate is meant for writing cleaner, more robust code, reducing conditional logic, and preventing common data synchronization errors. For that, there are a few key practices to consider and implement.
Validate Input Before Saving
While updateOrCreate is convenient, it bypasses model mass-assignment protection and can insert unvalidated data. Always validate your input beforehand, especially from user requests.
Example
// In your controller
$validated = $request->validate([
'email' => 'required|email',
'name' => 'required|string|max:255',
]);
// Then use the validated data
$user = User::updateOrCreate(
['email' => $validated['email']],
['name' => $validated['name']]
);
This ensures data integrity and application security.
Use Transactions for Bulk Operations
When performing multiple updateOrCreate operations in a loop (e.g., importing records), wrap the process in a database transaction. This guarantees that all operations succeed together or fail together. It prevents partial data updates that can corrupt your dataset.
Example
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
foreach ($users as $userData) {
User::updateOrCreate(
['email' => $userData['email']],
['name' => $userData['name']]
);
}
});
If one operation fails, the entire transaction is rolled back.
Log Updates for Audit & Debugging
The updateOrCreate method silently updates records, which can make tracking data changes difficult. Leverage Laravel’s model events, like updated and created, in the model’s booted method to log activity.
Example
// In your User model
protected static function booted()
{
static::updated(function ($user) {
logger("User updated.", ['user_id' => $user->id, 'changes' => $user->getChanges()]);
});
static::created(function ($user) {
logger("New user created.", ['user_id' => $user->id]);
});
}
This provides a clear audit trail for debugging and monitoring.
But even after following the due processes and the best practices, there’s a chance you may still end up with errors or mistakes.
Common Mistakes with Laravel updateOrCreate (& How to Avoid Them)
Let’s look at the common mistakes you may end up committing inadvertently.
Wrong Attribute-Value Structure
A frequent syntax error is misplacing the two arrays, leading to unexpected results or database errors.
The Mistake
// Incorrect: Attributes are scattered
$user = User::updateOrCreate(
'email', 'john@example.com', // This will cause an error
['name' => 'John']
);
The Solution
Always use two distinct arrays. The first is for the “search” attributes, the second for the “update/create” values.
// Correct: Two clear arrays
$user = User::updateOrCreate(
['email' => 'john@example.com'], // Search by this
['name' => 'John', 'email' => 'john@example.com'] // Set/update these
);
Mass Assignment Issues
updateOrCreate respects Laravel’s mass assignment protection. If you haven’t defined $fillable or $guarded on your model, the method will silently fail to insert or update the intended fields.
The Mistake
// If 'name' is not fillable in the User model...
$user = User::updateOrCreate(
['email' => 'john@example.com'],
['name' => 'John'] // 'name' will be ignored!
);
The Solution
Always define the fillable attributes in your Eloquent model.
// In app/Models/User.php
class User extends Model
{
protected $fillable = [
'email',
'name',
// ... other fields
];
}
Overlooking Unique Constraints & Duplicate Keys
The method relies on the first array to find a single record. If your search attributes aren’t unique (e.g., searching by a non-unique first_name), it will update the first record it finds, which might not be the one you intend.
The Mistake
// If multiple users have the first name "John"
$user = User::updateOrCreate(
['first_name' => 'John'], // Not a unique attribute!
['last_login' => now()]
);
// This updates the FIRST John it finds, potentially corrupting data.
The Solution
Always use a unique or compound unique key for the search attributes. This is the most critical rule for predictable behavior.
// Correct: Using a unique email
$user = User::updateOrCreate(
['email' => 'john@example.com'], // Unique identifier
['last_login' => now()]
);
// Correct: Using a compound unique key
$user = User::updateOrCreate(
['company_id' => 5, 'employee_id' => 101], // Compound unique key
['status' => 'active']
);
Ignoring the Return Value for Confirmation
A common oversight is not using the returned model instance. The method returns the updated or created model, which you should use to confirm the action.
The Mistake
// You have no reference to what happened
User::updateOrCreate([...], [...]);
// Did it create or update? What's the ID?
The Solution
Always capture the result to verify the operation and use the model.
$user = User::updateOrCreate([...], [...]);
// You can now check the outcome
if ($user->wasRecentlyCreated) {
logger("New user was created with ID: {$user->id}");
} else {
logger("Existing user was updated. ID: {$user->id}");
}
Wrapping Up
Laravel’s updateOrCreate method is a convenient tool for managing database records efficiently. By combining the logic of updating and creating records into a single method, it simplifies the process of ensuring data consistency.
By incorporating updateOrCreate into your Laravel projects, you can enhance your application’s efficiency and maintainability. Experiment with different use cases and explore the full potential of this valuable tool.
If you want to build a quality site with the best practices followed, contact us today!
FAQs About Laravel updateOrCreate
When should I use updateOrCreate over other methods?
Use updateOrCreate when you need to handle both creation and update scenarios in a single operation. It’s particularly useful for scenarios where you want to ensure that only one record exists with a specific set of attributes.
When should I use updateOrCreate?
You should use updateOrCreate when you need to ensure a record either exists and is updated or is created if it doesn’t exist. It’s commonly used in situations like:
– Updating user profiles.
– Managing inventory or product details.
– Synchronizing data from external sources.
Can I process, merge, or aggregate records managed by updateOrCreate using collections?
After performing upserts, you can use Laravel collections or refer to our guide on how to combine Laravel collections for advanced merging, filtering, or reporting tasks on your Eloquent results.
Can updateOrCreate handle bulk operations?
No, updateOrCreate is designed to handle a single record at a time. For bulk operations, you would need to loop through an array of data or use more optimized bulk update methods, like updateBatch.
Simplify Database Operations with updateOrCreate
Automate record management in Laravel using updateOrCreate for cleaner, faster, and smarter database handling. We can help you optimize your app’s data logic easily.


