Felix
Felix

Reputation: 2661

Laravel Command - Method Illuminate\Database\Eloquent\Collection::update does not exist

I created a command in Laravel to run on a task schedule.

Here is the command logic:

public function handle()
{
    $commentNotifications = CommentNotification::where('task_performed', 0)
    ->get();
    
    foreach ($commentNotifications as $commentNotification) {
        //blah blah
    }
    
    $commentNotifications->update(['task_performed' => 1]);


    $this->comment(sprintf('Completed %d CommentNotification(s)', $commentNotifications->count()));
}

however this returned the following error:

Method Illuminate\Database\Eloquent\Collection::update does not exist.

So I tried this instead:

    $commentNotifications->task_performed = 1;
    $commentNotifications->save();

but this returned:

Method Illuminate\Database\Eloquent\Collection::save does not exist.

Why is this happening?

Upvotes: 0

Views: 761

Answers (3)

Jason
Jason

Reputation: 3040

There are two issues here. One is your understanding of the Eloquent collection, and then your need to update multiple records with a single query.

Firstly, a collection is just a set of in-memory records that you can iterate through. The Eloquent collection is just an extension of that, where those records are pulled from a database, and typically has a set of models as the underlying items. It also has some extra methods to work with those models.

However, it is not directly tied to the database at all. This means that functions like update wouldn't work, and hence they do not exist.

For your need to update multiple records in the collection, you don't need to load them into memory first (unless you want to use them elsewhere). Simply create a query using the Builder, and call update on that query

CommentNotification::where('task_performed', 0)->update(['task_performed' = 1]);

This will create the expected SQL query:

UPDATE comment_notifications SET task_performed = 1 WHERE task_performed = 0;

Edit - To answer your query about the mass update:

If you need to only update a subset of records, you simply need to add a extra filter to the update

CommentNotification::whereIn('id', [1, 2, 3])
    ->where('task_performed', 0)
    ->update(['task_performed' = 1]);

This will update only the records with those IDs, and then only if the task is not performed. How you source the array of id values will be up to you.

Upvotes: 2

Guilherme Pedon
Guilherme Pedon

Reputation: 1

->get() returns a collection. Use a loop to update:

public function handle()
{
    $commentNotifications = CommentNotification::where('task_performed', 0)
    ->get();
    
    foreach ($commentNotifications as $commentNotification) {
        $commentNotification->task_performed = 1;
        $commentNotification->save();
    }
    
    $this->comment(sprintf('Completed %d CommentNotification(s)', $commentNotifications->count()));
}

Or, use Mass Updates.

CommentNotification::where('task_performed', 0)->update(['task_performed' => 1]);

Upvotes: 0

HijenHEK
HijenHEK

Reputation: 1296

you are using get() returns a collection therefore you cannot use update and save since they are methods of the eloquent model class use first() to get the first model instead of a collection , or use the update inside the foreach to update each item in your collections .

save() and update() exist in Illuminate\Database\Eloquent\Model;

for example

foreach ($commentNotifications as $commentNotification) {
        $commentNotification->update(['task_performed' => 1]);
    }

Upvotes: 0

Related Questions