概要
$users = [];
foreach ($parameters as $parameter) {
$users[] = User::create($parameter);
}
dump($users);
こんな感じで作ってしまうといざ大量のユーザーデータを挿入しようとするとメモリがいくつあっても足りません。
ということで一括挿入するコードに書き直します。
Bulk Insert
// Laravelは二重の配列を渡すと複数レコードを一括挿入できる
$data = [
['name' => 'Taylor', 'age' => 30],
['name' => 'Nuno', 'age' => 40],
];
User::insert($data);
insert関数の返り値はboolであり、挿入したレコードのIDを使いたい場合は使えません。
補足: insertGetId
$id = DB::table('users')->insertGetId(
['email' => 'john@example.com', 'votes' => 0]
);
公式で用意されてるじゃん!と思うんですが、一括挿入には対応していません。。
ということでひと工夫が必要です。
Bulk Insert(挿入したレコードの主キーを返す)
use App\Models\User;
use Illuminate\Support\Facades\DB;
$data = [
['name' => 'Taylor', 'age' => 30],
['name' => 'Nuno', 'age' => 40],
];
$userIds = DB::transaction(static function() use ($data): array {
User::insert($data);
$lastId = User::orderByDesc('id')->first()->id;
return range($lastId - count($data) + 1, $lastId);
});
トランザクションで囲って、User::insert($data);
で一括挿入しています。
これで途中に別のデータが差し込まれることを防ぎます。
最新のユーザーIDを取得して、開始の番号からの連番配列を作って返しています。
UUIDであれば前採番できるので、こういう工夫が要らなくて良いですね。
補足: DB::transaction(...) の結果はコールバック関数の返り値になる
特に公式ドキュメントには書かれてないですが、Tailorさんが言ってました。
割と使うので公式に使い方を載っけて欲しいな。