Collections
An Eloquent query returns a collection rather than an array — an object with dozens of methods for processing data. The methods chain together, and the code reads like a description of what you want to get.
Creating
get() and all() return a collection. The collect() function makes one from a plain array:
$numbers = collect([1, 2, 3, 4, 5]);
$posts = Post::all();Transforming and filtering
map() changes every item, filter() keeps the matching ones:
$titles = $posts->map(fn ($post) => strtoupper($post->title));
$popular = $posts->filter(fn ($post) => $post->views > 1000);
$even = collect([1, 2, 3, 4])->filter(fn ($n) => $n % 2 === 0)->values();values() renumbers the keys after filtering.
The values of one field
$titles = $posts->pluck('title');
$titlesById = $posts->pluck('title', 'id');
$list = $posts->pluck('title')->implode(', ');Searching
$first = $posts->first();
$firstPopular = $posts->first(fn ($post) => $post->views > 1000);
$post = $posts->firstWhere('slug', 'hello');
$hasDrafts = $posts->contains(fn ($post) => !$post->is_published);Totals
$total = $orders->sum('total');
$average = $orders->avg('total');
$biggest = $orders->max('total');
$count = $orders->count();These methods compute over data that is already loaded, without a new database query.
Sorting and grouping
$sorted = $posts->sortByDesc('views')->values();
$byCategory = $posts->groupBy('category_id');
$counts = $posts->countBy('category_id');
[$published, $drafts] = $posts->partition(fn ($post) => $post->is_published);groupBy() returns a collection of collections keyed by the field's values. partition() splits a collection in two by a condition.
Parts of a collection
$top = $posts->take(3);
$rest = $posts->skip(3);
$rows = $posts->chunk(4);
$unique = collect([1, 2, 2, 3])->unique()->values();chunk(4) splits into groups of four — handy for printing cards in rows.
A chain
$report = Order::with('user')->get()
->filter(fn ($order) => $order->status === 'paid')
->groupBy(fn ($order) => $order->user->name)
->map(fn ($orders) => $orders->sum('total'))
->sortDesc();The result is the total of paid orders per customer, from largest to smallest.
A collection or a query
Collection methods work in PHP memory, while builder methods work in the database. Whatever can be done with a query, do with a query:
| Task | In the database | In memory |
|---|---|---|
| Pick the published ones | Post::where(...)->get() | Post::all()->where(...) |
| Count | Post::count() | Post::all()->count() |
The right column loads the whole table only to throw most of it away.
Common mistake
Post::all()->count() and Post::count() give the same number, but the first loads every row of the table into memory. With ten records there is no difference; with a million the site crashes out of memory. Filter and count in the database, and use collections for what is already loaded.