古くなってもう要らない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つだけになっていました。いたれりつくせりです。
メルマガ購読の申し込みはこちらから。