Updating data in a database is one of the most common tasks in web application development. Whether you are building an inventory system, a blog, a customer management tool, or an e-commerce platform, you will constantly update records such as user profiles, product details, post content, orders, categories, and more. Laravel’s Eloquent ORM makes this process simple, expressive, secure, and highly readable.
In this extensive 3000-word guide, you will learn everything about updating data using Laravel Eloquent ORM. You will see how to retrieve a model, modify attributes, save updates, perform mass updates, update through query builder methods, validate data before updating, use timestamps, update relationships, handle events, apply optimistic locking, and understand best practices to avoid common mistakes.
This guide is suitable for beginners as well as those who want a deeper understanding of how Eloquent handles updates internally.
Understanding How Eloquent Updates Work
Before learning how to update data, you must understand how Eloquent interacts with database tables. Eloquent maps each table to a model, each record to a model instance, and each column to an attribute. When you modify an attribute in a model instance and call the save() method, Eloquent generates an SQL update query behind the scenes.
Example:
$product = Product::find(1);
$product->price = 1500;
$product->save();
This code represents the SQL query:
UPDATE products SET price = 1500, updated_at = NOW() WHERE id = 1;
Eloquent automatically handles:
- Attribute assignment
- Dirty checking (tracking changed values)
- Timestamp updates
- Model events
- SQL generation
- Parameter binding (protects from SQL injection)
Because of these features, developers can update records using clean and expressive code.
Retrieving a Model Before Updating
To update a record, you first retrieve it from the database. Eloquent provides several methods for this:
Product::find(1)
Product::where('id', 1)->first()
Product::firstOrFail()
Product::findOrFail(1)
The simplest is:
$product = Product::find(1);
If the record does not exist, $product will be null. To avoid this, you can use:
$product = Product::findOrFail(1);
This throws a 404 error if the record is missing.
Updating Attributes on the Model
Once you have retrieved the model instance, updating it is simple. You assign new values to model properties:
$product->name = "New Product Name";
$product->price = 1500;
$product->stock = 20;
These attributes correspond to columns in the database table. After assigning new values, call:
$product->save();
Eloquent automatically generates the SQL update statement.
Example output SQL (conceptually):
UPDATE products
SET name = "New Product Name",
price = 1500,
stock = 20,
updated_at = NOW()
WHERE id = 1;
You never have to write SQL manually.
Using the fill Method for Bulk Assignment
Instead of assigning each attribute individually, you can update multiple fields at once using fill():
$product->fill([
'name' => 'Monitor',
'price' => 900,
'stock' => 15
]);
$product->save();
To use fill(), you must specify fillable attributes in the model:
protected $fillable = ['name', 'price', 'stock'];
This prevents mass assignment vulnerabilities.
Using the update Method on the Model Instance
You can also update data using the update() method directly on the model instance:
$product->update([
'price' => 1800,
'stock' => 25
]);
This automatically saves the changes, so you do not need to call save() afterward.
Updating Records Without Retrieving Them First
Sometimes you want to update a record without loading it into memory. In this case, you can use the update() method on the query builder:
Product::where('category', 'Electronics')->update([
'discount' => 10
]);
This generates a direct update SQL query.
It updates multiple rows at once:
UPDATE products
SET discount = 10
WHERE category = 'Electronics';
This approach is faster and efficient for bulk updates but does not trigger model events.
Understanding Timestamps During Updates
Eloquent automatically updates the updated_at column whenever you call save() or update().
Example:
$product->price = 1500;
$product->save();
Automatically updates:
- updated_at
- Keeps created_at unchanged
If you want to disable timestamps in a model:
public $timestamps = false;
If you want custom timestamp fields:
const CREATED_AT = 'created_on';
const UPDATED_AT = 'modified_on';
Updating Only Changed Fields
Eloquent uses a feature called dirty checking. This means it only updates fields that have actually changed.
Example:
$product->name = $product->name;
$product->save();
No update query will run because nothing changed.
This avoids unnecessary database load and improves performance.
You can check if a model is dirty:
$product->isDirty();
Or check specific fields:
$product->isDirty('price');
Validating Data Before Updating
It is important to validate data before updating. This is usually done inside a controller:
$request->validate([
'name' => 'required|min:3',
'price' => 'required|numeric',
]);
Then update the record:
$product = Product::findOrFail($id);
$product->update($request->only('name', 'price'));
Validation prevents incorrect or harmful data from being saved.
Updating With Form Submissions
When updating records using an HTML form, you typically use the PUT or PATCH method.
Example route:
Route::put('/products/{product}', [ProductController::class, 'update']);
Example controller method:
public function update(Request $request, Product $product)
{
$product->update($request->all());
return redirect()->back();
}
Example form:
<form action="/products/{{ $product->id }}" method="POST">
@csrf
@method('PUT')
<input type="text" name="name" value="{{ $product->name }}">
<input type="number" name="price" value="{{ $product->price }}">
<button type="submit">Update</button>
</form>
This is how Laravel handles resource updates using RESTful conventions.
Updating JSON Fields
If your database column is a JSON type, Eloquent makes updates easy.
Example:
$user->settings = [
'theme' => 'dark',
'notifications' => true
];
$user->save();
Or update part of a JSON field:
User::where('id', 1)->update([
'settings->theme' => 'light'
]);
Updating Relationships
Sometimes you want to update related models.
Example: update a user’s profile
$user = User::find(1);
$user->profile->update(['bio' => 'New biography']);
Or update a product belonging to a category:
$category->products()->update(['discount' => 5]);
This applies an update to all related products.
Updating Pivot Tables in Many-to-Many Relationships
You can update pivot table fields using the updateExistingPivot method.
Example:
$user->roles()->updateExistingPivot($roleId, [
'level' => 'moderator'
]);
Pivot tables often store extra details about relationships.
Handling Model Events During Updates
Eloquent fires events automatically during updates:
- updating
- updated
- saving
- saved
Example:
protected static function booted()
{
static::updating(function ($product) {
// custom logic before update
});
}
Model events allow additional validations, logging, audit trails, and notifications.
Using Mutators When Updating Data
Mutators allow you to transform data before saving.
Example mutator:
public function setNameAttribute($value)
{
$this->attributes['name'] = strtolower($value);
}
Updating:
$product->name = 'Monitor';
$product->save();
Saved as:
monitor
Mutators ensure consistent data formats.
Using Accessors to Format Updated Data
Accessors allow formatting after retrieval.
Example:
public function getPriceAttribute($value)
{
return number_format($value, 2);
}
Updating does not affect accessors, but reading the updated value becomes formatted.
Using Transactions When Updating Data
For critical updates, you may want to use transactions.
Example:
DB::transaction(function () use ($product) {
$product->price = 200;
$product->stock = 10;
$product->save();
});
If one update fails, everything rolls back.
Preventing Conflicts With Optimistic Locking
Optimistic locking checks if another user updated the same record before your update.
Add a version column:
$table->integer('version')->default(1);
Update rule:
Product::where('id', $id)
->where('version', $currentVersion)
->update([
'price' => $newPrice,
'version' => $currentVersion + 1,
]);
This prevents overwriting other users’ changes.
Updating Large Volumes of Data
For bulk updates, use query builder updates:
Product::where('stock', '<', 5)->update(['status' => 'low']);
This updates all matching rows in one query, improving performance.
Avoid looping like this:
foreach($products as $product) {
$product->update([...]);
}
Because it sends multiple queries.
Avoiding Common Mistakes When Updating Data
Do not update without fillable attributes:
$product->update($request->all());
This can cause mass assignment issues. Use fillable fields or:
$product->update($request->only('name','price'));
Do not forget:
- Validate input
- Protect sensitive fields
- Use transactions for important updates
- Avoid overriding timestamps unnecessarily
- Avoid updating inside loops when possible
Updating Soft Deleted Models
If your model uses soft deletes:
use SoftDeletes;
You can still update soft deleted records:
$product = Product::withTrashed()->find(1);
$product->update(['status' => 'archived']);
Updating Records Using API Requests
When building APIs, updating follows JSON input.
Controller:
public function update(Request $request, Product $product)
{
$product->update($request->only('name','price'));
return response()->json($product);
}
Route:
Route::put('/products/{product}', [ProductController::class, 'update']);
Leave a Reply