Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to delete multiple records using Laravel Eloquent

Tags:

Now this, from what I can see, should have been simple.

I want to be able to delete multiple records from the database. I have the id's of all the records I wish to delete. I call the resource.destroy route using comma separated list of ids (id is of postgres type uuid), like so:

Request URL:http://foo.app/products/62100dd6-7ecf-4870-aa79-4b132e60c904,c4b369f1-d1ef-4aa2-b4df-b9bc300a4ff5
Request Method:DELETE

On the other end, my controller action looks like so:

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        $org->products()->find($ids)->delete();
    }
    catch(...) {
    }
}

This gives me the following error:

BadMethodCallException in Macroable.php line 81:
Method delete does not exist.

in Macroable.php line 81
at Collection->__call('delete', array()) in ProductsController.php line 251
at Collection->delete() in ProductsController.php line 251
at ProductsController->destroy('62100dd6-7ecf-4870-aa79-4b132e60c904,c4b369f1-d1ef-4aa2-b4df-b9bc300a4ff5')

I have verified that find() is returning a collection of products matching the specified ids.

What am I missing?

PS: 1. The model Product has several belongsTo relationships with other models. 2. The product.destroy code works fine if I pass it a single id

EDIT I guess, I'm also trying to understand what the difference between:

$org->products()->find($ids)->delete()

and

$org->products()->whereIn('id', $ids)->get()->delete()

is? From what I see, both find and get are returning Collections

like image 714
Code Poet Avatar asked Jan 27 '16 19:01

Code Poet


People also ask

How do you delete in laravel eloquent?

Laravel Eloquent Deleting You can delete data after writing it to the database. You can either delete a model instance if you have retrieved one, or specify conditions for which records to delete. To delete a model instance, retrieve it and call the delete() method: $user = User::find(1); $user->delete();

How do I remove all records from a table in laravel eloquent?

In the first example, we are going to use the truncate() function, which is used to delete all the records. In the second example, we will delete records on the basis of the id. So we will specify some id and use the delete() function to delete all the records of that particular id.


2 Answers

The issue is that you're calling delete() on a Collection, which does not have that method.

You have a couple options here.

Model Events

If you have event listeners for the deleting/deleted model events, you will need to make sure the deletion happens in a way that each model is loaded and then deleted.

In this case, you can use the destroy method on the model that takes a list of ids. It will load a new model for each id, and then call delete() on it. As you mention in a comment, it won't restrict the deletion to only those products in the organization, so you would need to filter out those ids before passing the list into the destroy() method.

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        // intersect the product ids for the org with those passed in
        $orgIds = array_intersect($org->products()->lists('id'), $ids);
        // now this will only destroy ids associated with the org
        \App\Product::destroy($orgIds);
    }
    catch(...) {
    }
}

If you don't particularly like that approach, you will need to iterate your collection of organization products and call delete() on them individually. You can use a standard foreach, or you can use the each method on the collection:

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        $org->products()->find($ids)->each(function ($product, $key) {
            $product->delete();
        });
    }
    catch(...) {
    }
}

No Model Events

Now, if you don't have any model events that you need to listen for, things are a little easier. In this case, you can just call delete() on the query builder, and it will go straight to deleting the records without loading any model objects. So, you get cleaner code with better performance:

public function destroy($id)
{
    try {
        $ids = explode(",", $id);
        // call delete on the query builder (no get())
        $org->products()->whereIn('id', $ids)->delete();
    }
    catch(...) {
    }
}
like image 107
patricus Avatar answered Sep 21 '22 12:09

patricus


If you create a model of your products, it will help you with these types of operations.

For example:

the model Products.php

<?php

namespace App\Http\Models;

use Illuminate\Database\Eloquent\Model;

class Products extends Model
{
    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'products';
    protected $primaryKey = 'id';

    protected $fillable = ['name', 'price', 'description'];


}

The controller Products.php

You can use the destroy method and pass one or more primary keys to it as arguments.

<?php

    namespace App\Http\Controllers;

    use App\Http\Models\Products;

    class Products 
    {
        
        public function destroy($id)
        {
            try {
                
                $ids = explode(",", $id);
                //$ids is a Array with the primary keys
                Products::destroy($ids);
            }
            catch(...) {
            }
        }

    }

You can also use this option to remove query results with a custom parameter

$deletedRows = Products::where('name', 'phones')->delete();

You can check the Laravel documentation https://laravel.com/docs/8.x/eloquent#soft-deleting

like image 27
Frank Jose Avatar answered Sep 18 '22 12:09

Frank Jose