Laravel Collectionのmergeでデータ結合処理を深掘り解説

by

カテゴリー:

Laravelのコレクション(Collection)は、配列データを直感的に操作するための便利なメソッドを数多く備えたクラスです。その中でもmergeメソッドは、複数のコレクションや配列を1つにまとめたいときに欠かせないメソッドです。

この記事では、mergeメソッドの基本的な使い方から、単純配列と連想配列での挙動の違い、mergeRecursiveunionconcatといった似たメソッドとの使い分け、そして実務での活用例までを整理して解説します。

この記事でわかること

  • mergeメソッドの基本構文と戻り値の考え方
  • 単純配列と連想配列でキーがどう扱われるかの違い
  • mergeunionconcatmergeRecursiveの使い分け
  • 実務でmergeが役立つ場面(デフォルト値の上書き、データの統合)
  • つまずきやすい注意点とその回避方法

mergeメソッドとは

mergeメソッドは、あるコレクションに対して別のコレクションや配列を結合し、新しいコレクションを返すメソッドです。呼び出し元のコレクションそのものは変更されない(非破壊的)ため、元データを保持したまま結合結果だけを別変数で受け取れます。

基本構文

// $collection: 結合元のコレクション
// $items: 結合するコレクションまたは配列
$new = $collection->merge($items);

まずは最もシンプルな例を見てみましょう。

$collection1 = collect([1, 2, 3]);
$collection2 = collect([4, 5, 6]);

$mergedCollection = $collection1->merge($collection2);

$mergedCollection->all(); // [1, 2, 3, 4, 5, 6]

この例では、mergeメソッドを使って$collection1$collection2を結合し、新しいコレクション$mergedCollectionを作成しています。$mergedCollection->all()を呼び出すことで、結合された結果を配列として確認できます。

単純配列と連想配列での挙動の違い

mergeメソッドで最もつまずきやすいのが、キーの扱いが配列の種類によって変わる点です。数値キー(単純配列)と文字列キー(連想配列)で結果が異なります。

  • 数値キーの場合:キーは振り直され、重複する値もそのまま追記される(要素は保持される)
  • 文字列キーの場合:同じキーが存在すると、あとから結合した側の値で上書きされる
$collection1 = collect([1, 2, 3]);
$collection2 = collect([2, 3, 4]);

$mergedCollection = $collection1->merge($collection2);

$mergedCollection->all();
// [1, 2, 3, 2, 3, 4]

$collection = collect(['id' => 1, 'price' => 100]);
$merged = $collection->merge(['price' => 200, 'discount' => false]);
$merged->all();

/*
    [
        'id' => 1,
        'price' => 200,
        'discount' => false,
    ]
*/

単純な配列では重複する要素を保持したまま結合し、連想配列では同名キー(price)の値が後勝ちで上書きされています。この「連想配列は上書き、単純配列は追記」というルールを押さえておくと、意図しない結果を防げます。

数値キーの場合は、元のキーの値が何であっても0から連番で振り直される(再採番)点も押さえておきましょう。次のように飛び番のキーを持つコレクションでも、結合後は末尾へ追加されたうえでキーが0から振り直されます。

$collection1 = collect([10 => 'a', 20 => 'b']);
$collection2 = collect([30 => 'c']);

$collection1->merge($collection2);
/*
    [
        0 => 'a',
        1 => 'b',
        2 => 'c',
    ]
*/

元の102030というキーは保持されず、0, 1, 2へ振り直されています。特定の数値キーを維持したまま補完したい場合は、キーを尊重するunionを使います(後述の比較表を参照)。

merge・union・concat・mergeRecursiveの使い分け

Laravel Collectionには結合系のメソッドが複数あり、PHP標準のarray_mergeとも挙動が異なります。目的に応じて使い分けられるよう、代表的なメソッドを比較表にまとめました。

メソッド戻り値/破壊性同名キーの扱い特徴・用途
merge新コレクション(非破壊)後勝ちで上書きあとから渡した値を優先したいとき(設定の上書きなど)
union新コレクション(非破壊)元のコレクションを優先(先勝ち)既存の値やキーを残しつつ、足りないキーだけ補完したいとき
concat新コレクション(非破壊)キーを無視して末尾に追加キーを気にせず単純に要素をつなげたいとき
mergeRecursive新コレクション(非破壊)同名キーは配列にまとめる多次元配列を階層ごとに再帰的に結合したいとき
push元コレクションを変更(破壊的)末尾に1要素だけ追加コレクションや配列ではなく「単一の値」を1つ追加したいとき
array_merge(PHP標準)新しい配列を返す数値キーは再採番・文字列キーは後勝ちコレクションではなく素の配列同士を結合するとき

pushだけは他と性質が異なり、コレクションそのものを書き換える破壊的メソッドで、渡すのはコレクションや配列ではなく単一の値です。「コレクション同士をつなげたい」のか「値を1つ足したい」のかでmergeconcatpushを選び分けます。素の配列同士であればcollect()を挟まずPHPのarray_mergeで済む場面も多く、キーの扱いはmergeと同じ考え方(数値キーは再採番・文字列キーは後勝ち)です。

unionとの違い(先勝ち/後勝ち)

$base = collect(['name' => '山田', 'role' => 'user']);
$add  = ['role' => 'admin', 'active' => true];

$base->merge($add)->all();
// ['name' => '山田', 'role' => 'admin', 'active' => true]  // roleは後勝ち

$base->union($add)->all();
// ['name' => '山田', 'role' => 'user', 'active' => true]   // roleは元の値を維持

「渡した値で上書きしたい」ならmerge、「元の値を優先して足りない分だけ補いたい」ならunionと覚えておくと選びやすくなります。

mergeRecursiveで多次元配列を結合する

$collection = collect(['id' => 1, 'role' => ['editor']]);
$merged = $collection->mergeRecursive([
    'id'   => 2,
    'role' => ['admin'],
]);

$merged->all();
/*
    [
        'id'   => [1, 2],
        'role' => ['editor', 'admin'],
    ]
*/

mergeRecursiveは、同名キーの値を上書きせずに配列としてまとめます。設定値やタグのように「複数の値を合成したい」ケースで役立ちます。

実務でmergeが役立つ場面

デフォルト値をリクエスト値で上書きする

$defaults = collect([
    'per_page' => 20,
    'sort'     => 'created_at',
    'order'    => 'desc',
]);

// リクエストで指定された値だけを上書き
$options = $defaults->merge($request->only(['per_page', 'sort', 'order']));

デフォルト設定をベースに、ユーザーが指定した項目だけを上書きする——という処理はmergeの典型的な使いどころです。指定がない項目はデフォルト値がそのまま残ります。

複数ソースのデータを1つにまとめる

キャッシュから取得したデータとデータベースの結果を統合したり、APIレスポンスをまとめたりする際にもmergeが活躍します。元のコレクションを壊さないため、結合前後のデータを比較しながら処理を組み立てられます。

Eloquent Collectionを結合するときの注意点

ここまではcollect()で作った基本のIlluminate\Support\Collectionを前提にしてきましたが、Eloquentクエリの結果(Model::all()->get())はIlluminate\Database\Eloquent\Collectionという別クラスです。このクラスのmergeは挙動が上書きされており、配列キーではなくモデルの主キー(通常はid)で重複を判定します

$usersA = User::whereIn('id', [1, 2])->get(); // id=1, id=2
$usersB = User::whereIn('id', [2, 3])->get(); // id=2, id=3

$merged = $usersA->merge($usersB);
$merged->pluck('id')->all();
// [1, 2, 3] ← id=2 は重複せず、$usersB 側のモデルで上書きされる

基本のコレクションならid=2のモデルが2件残りますが、Eloquent Collectionでは同じ主キーのモデルは1件にまとめられ、あとから結合した側のモデルで置き換わります。複数のクエリ結果を重複なく統合したいときに便利な反面、「両方のレコードを残したい」場合は意図しない結果になります。次の点に注意してください。

  • まだ保存していないモデル(主キーが未採番のnew Userなど)は主キーで判定できないため、重複扱いされず両方残ることがあります。
  • 属性値だけを単純に足し合わせたい場合は、toBase()で基本コレクションに変換してからmergeすると、配列キー基準の挙動に戻せます。
  • 重複を主キーで消したくない・順序を制御したいときは、concatで連結してからunique('id')で明示的に絞り込むほうが意図が明確です。

期待と異なる結果になりやすい失敗例

mergeは挙動を誤解しやすいメソッドです。実際にハマりやすいパターンを、原因と対処法とあわせて整理します。

失敗例1:重複が消えると思っていた

$a = collect([1, 2, 3]);
$b = collect([3, 4]);

$a->merge($b)->all();
// 期待:[1, 2, 3, 4]
// 実際:[1, 2, 3, 3, 4] ← 数値キーでは重複は排除されない

// 重複を除きたいなら unique() を続ける
$a->merge($b)->unique()->values()->all(); // [1, 2, 3, 4]

失敗例2:戻り値を受け取っていない

$options = collect(['per_page' => 20]);

$options->merge(['per_page' => 50]); // 戻り値を捨てている
$options->get('per_page'); // 20 のまま(mergeは非破壊)

// 正しくは戻り値を受け取る
$options = $options->merge(['per_page' => 50]);
$options->get('per_page'); // 50

失敗例3:ネストした配列まで結合されると思っていた

$config = collect(['options' => ['a' => 1]]);
$merged = $config->merge(['options' => ['b' => 2]]);

$merged->get('options');
// 期待:['a' => 1, 'b' => 2]
// 実際:['b' => 2] ← options キーごと後勝ちで上書きされる

// 階層ごとに結合したいなら mergeRecursive
$config->mergeRecursive(['options' => ['b' => 2]])->get('options');
// ['a' => 1, 'b' => 2]

いずれも「mergeは浅く・非破壊で結合し、数値キーの重複は残す」という原則を押さえていれば防げます。重複排除はunique、階層結合はmergeRecursive、キー維持はunion——と目的別に組み合わせて使いましょう。

mergeを使うときの注意点

  • 連想配列は上書きされる:同名キーがある場合、あとから渡した値で置き換わります。値を残したい場合はunionを検討してください。
  • 非破壊的であるmergeは新しいコレクションを返すだけで、元の変数は変わりません。結果は必ず戻り値を受け取って使います。
  • ネストした配列は浅く結合される:多次元配列を階層ごとに結合したい場合はmergeではなくmergeRecursiveを使います。

関連するCollectionメソッド

コレクションを使いこなすうえで、結合以外のメソッドもあわせて押さえておくと処理の幅が広がります。用途に合わせて次の記事も参考にしてください。

まとめ

mergeメソッドは、配列やコレクションを非破壊的に結合できる便利なメソッドです。単純配列では要素を追記し、連想配列では同名キーを後勝ちで上書きするという挙動の違いを理解しておくことがポイントです。

「元の値を優先したいならunion」「キーを無視してつなげたいならconcat」「多次元配列を階層ごとにまとめたいならmergeRecursive」と、目的に応じて使い分けることで、Laravelのコレクション操作をより効果的に活用できます。

ホーム » 記事一覧 » 技術メモ » 開発 » Laravelテクニック » Laravel Collectionのmergeでデータ結合処理を深掘り解説

投稿者

ここまで読んでいただき、ありがとうございます。

このサイトでは、私自身が関わっていることや、興味を持って試していることをそのまま置いています。

内容を見ていて、
「少し話を聞いてみたい」
「協業できる部分がありそう」
と感じる点があれば、下記のお問い合わせフォームからご連絡ください。状況を確認したうえで、必要な範囲でお返事します。

特に、以下のWordPressサイトに関する相談にも対応しているのでご興味ありましたらご相談ください。


Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です