Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Merge Two Eloquent Collections?

I have a questions table and a tags table. I want to fetch all questions from tags of a given question. So, for example, I may have the tags "Travel," "Trains" and "Culture" attached to a given question. I want to be able to fetch all questions for those three tags. The tricky, so it seems, is that questions and tags relationship is a many-to-many defined in Eloquent as belongsToMany.

I thought about trying to merge the questions Collections as below:

foreach ($question->tags as $tag) {     if (!isset($related)) {         $related = $tag->questions;     } else {         $related->merge($tag->questions);     } } 

It doesn't seem to work though. Doesn't seem to merge anything. Am I attempting this correctly? Also, is there perhaps a better way to fetch a row of rows in a many-to-many relationship in Eloquent?

like image 700
Martyn Avatar asked May 29 '15 06:05

Martyn


People also ask

How to merge 2 collections in Laravel?

Laravel collection merge() method merge any given array to first collection array. If the first collection is indexed array, the second collection will be added to the end of the new collection. The merge() method can accept either an array or a Collection instance.

How do I combine two objects in laravel?

$new_collection = $collection->merge($other_collection) . This works in Laravel 4 and seems to handle both arrays and collections. Show activity on this post. What you can do here is merge the arrays of the two query result and then use the Response with json output like shown below.


2 Answers

The merge method returns the merged collection, it doesn't mutate the original collection, thus you need to do the following

$original = new Collection(['foo']);  $latest = new Collection(['bar']);  $merged = $original->merge($latest); // Contains foo and bar. 

Applying the example to your code

$related = new Collection();  foreach ($question->tags as $tag) {     $related = $related->merge($tag->questions); } 
like image 155
Wader Avatar answered Sep 21 '22 22:09

Wader


The merge() method on the Collection does not modify the collection on which it was called. It returns a new collection with the new data merged in. You would need:

$related = $related->merge($tag->questions); 

However, I think you're tackling the problem from the wrong angle.

Since you're looking for questions that meet a certain criteria, it would probably be easier to query in that manner. The has() and whereHas() methods are used to generate a query based on the existence of a related record.

If you were just looking for questions that have any tag, you would use the has() method. Since you're looking for questions with a specific tag, you would use the whereHas() to add the condition.

So, if you want all the questions that have at least one tag with either 'Travel', 'Trains', or 'Culture', your query would look like:

$questions = Question::whereHas('tags', function($q) {     $q->whereIn('name', ['Travel', 'Trains', 'Culture']); })->get(); 

If you wanted all questions that had all three of those tags, your query would look like:

$questions = Question::whereHas('tags', function($q) {     $q->where('name', 'Travel'); })->whereHas('tags', function($q) {     $q->where('name', 'Trains'); })->whereHas('tags', function($q) {     $q->where('name', 'Culture'); })->get(); 
like image 29
patricus Avatar answered Sep 20 '22 22:09

patricus