php - How to update and delete records in a table based on a new request? - Stack Overflow

I need to update records for Guide Steps (Every recipe has stepsinstruction and my table was created f

I need to update records for Guide Steps (Every recipe has steps/instruction and my table was created for storing this data)

I was able to create those records in the db with quite easy syntax:

GuideStep::insert($groupedSteps); // $groupedSteps is an array

But now I need to update those records (and remove unnecessary ones), for this moment I came up with logic that can only update records or create if there is no such records:

foreach ($groupedSteps as $step){
  GuideStep::updateOrInsert(
    ['recipe_id' => $recipeId, 'step_number' => $step['step_number']],
    ['step_text' => $step['step_text'], 'step_image' => $step['step_image']]
  );
}

migration:

Schema::create('guide_steps', function (Blueprint $table) {
            $table->id();
            $table->foreignId('recipe_id')->constrained()->cascadeOnDelete();
            $table->integer('step_number');
            $table->text('step_text');
            $table->string('step_image')->default('recipes-images/default/default_photo.png');
            $table->timestamps();
        });

I thought that I'll be able to use upsert() but this method requires unique columns (I don't have those)

Be grateful for some advices

I need to update records for Guide Steps (Every recipe has steps/instruction and my table was created for storing this data)

I was able to create those records in the db with quite easy syntax:

GuideStep::insert($groupedSteps); // $groupedSteps is an array

But now I need to update those records (and remove unnecessary ones), for this moment I came up with logic that can only update records or create if there is no such records:

foreach ($groupedSteps as $step){
  GuideStep::updateOrInsert(
    ['recipe_id' => $recipeId, 'step_number' => $step['step_number']],
    ['step_text' => $step['step_text'], 'step_image' => $step['step_image']]
  );
}

migration:

Schema::create('guide_steps', function (Blueprint $table) {
            $table->id();
            $table->foreignId('recipe_id')->constrained()->cascadeOnDelete();
            $table->integer('step_number');
            $table->text('step_text');
            $table->string('step_image')->default('recipes-images/default/default_photo.png');
            $table->timestamps();
        });

I thought that I'll be able to use upsert() but this method requires unique columns (I don't have those)

Be grateful for some advices

Share Improve this question edited Mar 26 at 8:03 Dmytro Shved asked Mar 26 at 7:01 Dmytro ShvedDmytro Shved 337 bronze badges 0
Add a comment  | 

3 Answers 3

Reset to default 2

I have also came up with approach when I am deleting all records (all steps) and inserting them:

if ($this->recipeId != 0) {
    GuideStep::where('recipe_id', $recipeId)->delete();
}
 GuideStep::insert($groupedSteps);

What do you think?

You must update existing steps, create new ones, and remove unnecessary ones. Since your guide_steps table does not have a unique constraint on recipe_id and step_number. You can't use upsert(). Instead, you can try the following approach:

  • Fetch existing steps for the given recipe_id.

  • Determine which steps need to be updated, inserted, or deleted.

  • Perform batch updates, inserts, and deletions efficiently.

Code Example:

use App\Models\GuideStep;
use Illuminate\Support\Facades\DB;

function updateGuideSteps($recipeId, $groupedSteps) {
    // Fetch existing steps
    $existingSteps = GuideStep::where('recipe_id', $recipeId)
        ->pluck('id', 'step_number') 
        ->toArray();

    $newStepNumbers = [];
    $insertData = [];
    $updateData = [];

    foreach ($groupedSteps as $step) {
        $stepNumber = $step['step_number'];
        $newStepNumbers[] = $stepNumber;

        if (isset($existingSteps[$stepNumber])) {
            // Prepare update data
            $updateData[] = [
                'id' => $existingSteps[$stepNumber],
                'step_text' => $step['step_text'],
                'step_image' => $step['step_image'],
                'updated_at' => now(),
            ];
        } else {
            // Prepare insert data
            $insertData[] = [
                'recipe_id' => $recipeId,
                'step_number' => $stepNumber,
                'step_text' => $step['step_text'],
                'step_image' => $step['step_image'],
                'created_at' => now(),
                'updated_at' => now(),
            ];
        }
    }

    // Perform batch insert
    if (!empty($insertData)) {
        GuideStep::insert($insertData);
    }

    // Perform batch update
    if (!empty($updateData)) {
        $table = (new GuideStep)->getTable();
        $cases = [];
        $ids = [];
        $bindings = [];

        foreach ($updateData as $data) {
            $id = (int) $data['id'];
            $ids[] = $id;
            $cases[] = "WHEN id = ? THEN ?";
            $bindings[] = $id;
            $bindings[] = $data['step_text'];
        }

        $sql = "UPDATE {$table} SET step_text = CASE " . implode(" ", $cases) . " END WHERE id IN (" . implode(',', $ids) . ")";
        DB::update($sql, $bindings);
    }

    // Delete steps that are not in the new set
    GuideStep::where('recipe_id', $recipeId)
        ->whereNotIn('step_number', $newStepNumbers)
        ->delete();
}

The upsert() method as per documentation requires a unique identifier. Looking by the way you are updating or creating your GuideStep you'd need something of the sort:

foreach ($groupedSteps as $step){
  GuideStep::upsert(
    [
        'recipe_id' => $recipeId, 
        'step_number' => $step['step_number']
        'step_text' => $step['step_text']
        'step_image' => $step['step_image']
    ],
    uniqueBy: ['recipe_id', 'step_number'],
    update: ['step_text', 'step_image']
  );
}

You can check more on how it is used here.
Deleting then creating instead of updating is a very bad idea due to a couple of reasons, you can check this discussion.

I haven't tested the code but it should work right off the bat.

Also, make sure to always validate your request in the controller, so that no surprise data comes in

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744160713a4561079.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信