古くなってもう要らないDBレコードを削除することを、プルーン(prune)あるいはパージ(purge)などと言います。カスタムのArtisanのコマンドを書いて処理してもいいのだけれど、LaravelではこれがModelの中であるトレイトを使うだけで、組織的できてしまいます。
プルーンの対象は特定のDBモデルのレコードです。ここでは、会員ログインのレコードを貯めているuser_logsのテーブルのモデルUserLog
を例とします。以下のようにPrunableのトレイトを追加して、削除したい対象のクエリーの条件をprunable()
で定義するだけです。
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Prunable; class UserLog extends Model { use HasFactory; use Prunable; const UPDATED_AT = null; // updated_atの項目はない /** * Get the prunable model query. * * @return \Illuminate\Database\Eloquent\Builder */ public function prunable() { return static::where('created_at', '<=', now()->subYear()); // 1年以上昔のレコードが対象 } }
そして、以下のコマンドの実行をクロンに設定にします。
$ php artisan model::prune
簡単でしょう。
削除する前に以下のように実際の削除なしの予行も可能です。
$ php artisan model:prune --pretend 8 [App\Models\UserLog] records will be pruned.
8個のレコードが削除されるよ、と知らせてくれます
tinkerで実際にプルーンを実行してみましょう。どのようなSQL文が実行されるか興味あります。
>>> Artisan::call('model:prune'); => 0 >>> sql(); => [ [ "query" => "select count(*) as aggregate from `user_logs` where `created_at` <= ?", "bindings" => [ Illuminate\Support\Carbon @1616039564 {#3572 date: 2021-03-18 03:52:44.536379 UTC (+00:00), }, ], "time" => 4.94, ], [ "query" => "select * from `user_logs` where `created_at` <= ? order by `id` asc limit 1000", "bindings" => [ Illuminate\Support\Carbon @1616039586 {#3546 date: 2021-03-18 03:53:06.837232 UTC (+00:00), }, ], "time" => 1.36, ], [ "query" => "delete from `user_logs` where `id` = ?", "bindings" => [ 1, ], "time" => 7.25, ], [ "query" => "delete from `user_logs` where `id` = ?", "bindings" => [ 2, ], "time" => 3.11, ], ...
なるほど、1個1個レコードは削除されるのですね。これは、モデルのdeletingやdeletedのイベント処理を可能にするためです。
そのイベント処理が必要でないなら、一括実行も可能です。トレイトをPrunable
からMassPrunable
にするだけです。
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\MassPrunable; class UserLog extends Model { use HasFactory; use MassPrunable; const UPDATED_AT = null; /** * Get the prunable model query. * * @return \Illuminate\Database\Eloquent\Builder */ public function prunable() { return static::where('created_at', '<=', now()->subYear()); // 1年以上昔のレコードが対象 } }
再度、tinkerでSQL文をチェックすると、
>>> Artisan::call('model:prune'); => 0 >>> sql(); => [ [ "query" => "delete from `user_logs` where `created_at` <= ? limit 1000", "bindings" => [ Illuminate\Support\Carbon @1616039978 {#3567 date: 2021-03-18 03:59:38.916448 UTC (+00:00), }, ], "time" => 5.61, ], ] >>>
削除のSQL文1つだけになっていました。いたれりつくせりです。
メルマガ購読の申し込みはこちらから。