Reputation: 3993
I have a simple set-up of Albums and Images, each album has many images. I can get all the data fine but I want to limit the returned number of images to 3. I have tried passing a closure like so:
Album::with(['images' => function($query) { $query->take(3);}])->get();
This does limit the number of images to 3 but it limits the total count of images to 3 but I want to limit each album to 3 images. So the first album will show 3 images as expected but all the other albums have no images.
I have tried adding a new method to my model like so:
public function limitImages()
{
return $this->hasMany('App\Image')->limit(3);
}
And I call this in my controller:
Album::with('limitImages')->get();
But this doesn't limit the image count returned at all
Upvotes: 11
Views: 18362
Reputation: 1311
Laravel 11+ allows limiting the number of eager loading results per parent using window functions.
The staudenmeir/eloquent-eager-limit
package has been merged into Laravel 11+ and eager loading limits are now supported natively.
Links:
Package documentation says about merge into Laravel
https://packagist.org/packages/staudenmeir/eloquent-eager-limit
Eager Load Limit announcement
https://laravel-news.com/eager-load-limit
Upvotes: 0
Reputation: 91
For those who don't mind the N + 1 issue, and maybe even prefer it.
On the Album model, have a custom attribute that returns the limited relations, i.e.
class Album extends Model
{
public function images(): hasMany
{
return $this->hasMany('App\Image');
}
public function getLimitedImagesAttribute()
{
return $this->images()->take(3)->get();
}
}
In your controller:
class MainController extends Controller
{
return Album::select('name')->get()->each->append('limited_images')
}
NOTE: This method will run N + 1
queries, where N
is the number of albums in the database. This method may be preferred if the number of rows in the Album table is not too large, but the related image table is too large.
Upvotes: 3
Reputation: 74
the take()
eloquent method just adds 'limit' word at the end of the query. this type of query is more complex and isn't supported by vanilla eloquent.
fortunately, there is an additional package called eloquent-eager-limit, which helps with this problem. in order to make it work, install that package by using composer require staudenmeir/eloquent-eager-limit
command and put use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
line inside both parent and children model classes.
Upvotes: 0
Reputation: 6345
I feel you'd quickly run into an N+1 issue trying to accomplish this. Just do it in the collection that it returns:
Album::with('images')->get()->map(function($album) {
$album->setRelation('images', $album->images->take(3));
return $album;
});
Upvotes: 18