8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Laravel Bulk Insert の後に主キーを返す

Last updated at Posted at 2023-08-29

概要

$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さんが言ってました。

割と使うので公式に使い方を載っけて欲しいな。

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?