I’m trying to merge several collections but I’m not able to do this for any reason. My code looks like that:
$restaurant = AppRestaurant::find(3);
$images = $restaurant->images;
$userimages = $restaurant->userimages;
$hours = $restaurant->hours;
$collectionMerge1 = $images->merge($userimages)->merge($hours);
$collectionMerge2 = $restaurant->userimages->merge($hours)->merge($images);
$collectionMerge3 = collect(array_merge($images->all(), $userimages->all(), $hours->all()));
The only merge that works is the last one. The previous ones are not showing all items that the collections contains. Why is this? What am I doing wrong?
If you take a look to the picture you will see that there are missing objects in merges 1 and 2. I’ve tried several ways to do that, but only works the last one. Maybe the merge method is having issues with keys?
Given that each of your values actually represents a proper collection (established through relationships), you should use push
instead of merge
. This is because merge
will actually overwrite certain elements when the key pairs already match:
$aggregates = collect([]);
$aggregates ->push($images)->push($userImages)->push($hours);
dd($aggregates ); //as expected
In general i feel there is a lot of pitfalls with merge, i think (in your case) most of the problems arises when you somehow tries to merge key value arrays together or concat
indexed arrays. My solution for this problem, is to use concat
instead of merging. Concat
adds another collection or array to the end of the current. So you will not get weird cases, as shown here.
$images->concat($userimages)->concat($hours);
This is old, but for posterity.
Let me give you simple example – easier to understand, than your collections.
It will be applied to yours at the bottom.
What you describe happens when initial Eloquent collection: $cars – has same id key as one of the following collections.
e.g. $cars has same id as element from $bikes
If you use it like this:
$vehicles = $cars->merge($bikes);
… you will get overwrite.
You get same overwrite, when you use it in this fashion as well:
$vehicles = $cars->merge($buses)->merge($bikes);
Regardless, where you put bikes when merging.
There is a simple workaround:
$vehicles = collect();
$vehicles = $vehicles->merge($buses)->merge($bikes)->merge($cars);
In this case, since your initial collection has no elements, it cannot conflict with any following collection and you get no overwrites.
It should work in any merging order, as long as empty collection comes first.
In your example, instead of:
$collectionMerge1 = $images->merge($userimages)->merge($hours);
You should do something like this:
$collectionMerge1 = collect();
$collectionMerge1 = $collectionMerge1->merge($images)->merge($userimages)->merge($hours);
Since empty collection is a base collection for merging, it does not mess with any following collection as it has no elements.