3
respostas

Bulk update com 1 query

Fala pessoal segue a maneira que encontrei aqui pra fazer o update com 1 ida ao banco, provavelmente tem coisa melhor mas tá ai o desafio:

$watchedEpisodes = implode(', ', $request->episodes ?? []);
DB::transaction(function () use ($watchedEpisodes, $season) {
    DB::table('episodes')->where('season_id', $season->id)
        ->update(['watched' => DB::raw("case when id in ($watchedEpisodes) then 1 else 0 end")]);
});
3 respostas

Gostei muito da sua abordagem. Ela resolve.

Se me permitir, gostaria de sugerir algo e saber sua opinião sobre:

- Uma sugestão para melhorar o código acima é utilizar a função "pluck" do Eloquent para obter apenas os IDs dos episódios assistidos, ao invés de usar implode e DB::raw. Isso tornaria o código mais legível e fácil de entender.

Outra sugestão é usar o método "updateOrInsert" do Eloquent, para atualizar ou inserir novos registros de forma mais eficiente.

$watchedEpisodeIds = $request->episodes ?? [];
$season->episodes()->whereIn('id', $watchedEpisodeIds)->updateOrInsert(['watched' => 1]);

E para tornar mais seguro, eu usaria o método whereIn para evitar SQL injection.

$watchedEpisodeIds = $request->episodes ?? [];
$watchedEpisodeIds = array_map('intval', $watchedEpisodeIds);
$season->episodes()->whereIn('id', $watchedEpisodeIds)->updateOrInsert(['watched' => 1]);

E é sempre recomendado usar transações para garantir a integridade dos dados, caso ocorra algum erro, o banco de dados será revertido.

DB::transaction(function () use ($watchedEpisodeIds, $season) {
    $season->episodes()->whereIn('id', $watchedEpisodeIds)->updateOrInsert(['watched' => 1]);
});

Você acha que funcionária legal e resolveria o proposto no exercício?

Como recebemos um array de inteiros (os ids dos checkboxes) do front acredito que esse array não teria o método pluck de uma Collection.

O método updateOrInsert eu já descartaria se possível pois o intuito é atualizar e nunca inserir.

O problema dessa abordagem é que ela apenas marca os episódios assistidos e não atualiza os desmarcados.

Ai que entra o case usado no DB::raw.

Sim é importante estar em uma transaction eu tinha omitido essa parte pois não era o foco da solução mas bem lembrado.

Refatorando novamente fica assim:

    $watchedEpisodes = implode(', ', $request->episodes ?? []);
    DB::transaction(function () use ($watchedEpisodes, $season) {
        $season->episodes()->update(['watched' => DB::raw("case when id in ($watchedEpisodes) then 1 else 0 end")]);
    });

E vamos indo até ficar bonito hehe

Muito bom. Concordo com suas observações.