Laravel Framework

Laravel Collections - Powerful Data Manipulation

18 min Lesson 14 of 45

Introduction to Collections

Collections are one of Laravel's most powerful features. They provide a fluent, convenient wrapper for working with arrays of data. Think of collections as arrays on steroids - they offer dozens of methods for filtering, mapping, reducing, and transforming data in elegant ways.

Note: Every Eloquent query that returns multiple results returns a Collection instance. You can also create collections manually from any array of data.

Creating Collections

There are multiple ways to create collections:

<?php use Illuminate\Support\Collection; // From array using collect() helper $collection = collect([1, 2, 3, 4, 5]); // Using Collection class $collection = new Collection(['apple', 'banana', 'orange']); // From Eloquent query (automatic) $users = User::all(); // Returns Collection $posts = Post::where('published', true)->get(); // Returns Collection // Empty collection $empty = collect(); // From range $numbers = collect(range(1, 10));

Basic Collection Methods

Let's explore fundamental collection methods:

<?php $collection = collect([1, 2, 3, 4, 5]); // all() - Get all items as array $array = $collection->all(); // [1, 2, 3, 4, 5] // count() - Count items $count = $collection->count(); // 5 // first() - Get first item $first = $collection->first(); // 1 // last() - Get last item $last = $collection->last(); // 5 // isEmpty() - Check if empty $isEmpty = $collection->isEmpty(); // false // isNotEmpty() - Check if not empty $isNotEmpty = $collection->isNotEmpty(); // true

Transforming Collections with map()

The map() method transforms each item in the collection:

<?php // Double each number $numbers = collect([1, 2, 3, 4, 5]); $doubled = $numbers->map(function ($number) { return $number * 2; }); // [2, 4, 6, 8, 10] // Using arrow functions (PHP 7.4+) $doubled = $numbers->map(fn($n) => $n * 2); // Map user objects to names $users = User::all(); $names = $users->map(function ($user) { return $user->name; }); // Map with key and value $products = collect([ ['name' => 'Desk', 'price' => 200], ['name' => 'Chair', 'price' => 100], ]); $formatted = $products->map(function ($product) { return $product['name'] . ': $' . $product['price']; }); // ['Desk: $200', 'Chair: $100']

Filtering Collections with filter()

The filter() method filters collection items based on a callback:

<?php // Filter even numbers $numbers = collect([1, 2, 3, 4, 5, 6]); $even = $numbers->filter(function ($number) { return $number % 2 === 0; }); // [2, 4, 6] // Filter users by role $users = User::all(); $admins = $users->filter(function ($user) { return $user->role === 'admin'; }); // Filter truthy values $values = collect([1, 2, null, 4, false, 6]); $truthy = $values->filter(); // [1, 2, 4, 6] // reject() - opposite of filter() $numbers = collect([1, 2, 3, 4, 5]); $odd = $numbers->reject(function ($number) { return $number % 2 === 0; }); // [1, 3, 5]

Extracting Values with pluck()

The pluck() method retrieves values for a given key:

<?php // Pluck names from array of arrays $users = collect([ ['name' => 'John', 'age' => 30], ['name' => 'Jane', 'age' => 25], ['name' => 'Bob', 'age' => 35], ]); $names = $users->pluck('name'); // ['John', 'Jane', 'Bob'] // Pluck with key $namesByAge = $users->pluck('name', 'age'); // [30 => 'John', 25 => 'Jane', 35 => 'Bob'] // Pluck from Eloquent models $users = User::all(); $emails = $users->pluck('email'); // Pluck nested values using dot notation $posts = collect([ ['title' => 'Post 1', 'author' => ['name' => 'John']], ['title' => 'Post 2', 'author' => ['name' => 'Jane']], ]); $authorNames = $posts->pluck('author.name'); // ['John', 'Jane']

Reducing Collections with reduce()

The reduce() method reduces a collection to a single value:

<?php // Sum of numbers $numbers = collect([1, 2, 3, 4, 5]); $sum = $numbers->reduce(function ($carry, $item) { return $carry + $item; }, 0); // 15 // Concatenate strings $words = collect(['Hello', 'World', 'from', 'Laravel']); $sentence = $words->reduce(function ($carry, $word) { return $carry . ' ' . $word; }); // " Hello World from Laravel" // Build associative array $products = collect([ ['id' => 1, 'name' => 'Desk'], ['id' => 2, 'name' => 'Chair'], ]); $indexed = $products->reduce(function ($carry, $product) { $carry[$product['id']] = $product['name']; return $carry; }, []); // [1 => 'Desk', 2 => 'Chair']
Tip: For simple summation, use the sum() method instead of reduce: $numbers->sum()

Grouping with groupBy()

The groupBy() method groups collection items by a given key:

<?php // Group users by role $users = collect([ ['name' => 'John', 'role' => 'admin'], ['name' => 'Jane', 'role' => 'user'], ['name' => 'Bob', 'role' => 'admin'], ['name' => 'Alice', 'role' => 'user'], ]); $grouped = $users->groupBy('role'); /* [ 'admin' => [ ['name' => 'John', 'role' => 'admin'], ['name' => 'Bob', 'role' => 'admin'], ], 'user' => [ ['name' => 'Jane', 'role' => 'user'], ['name' => 'Alice', 'role' => 'user'], ], ] */ // Group by callback $products = collect([ ['name' => 'Desk', 'price' => 200], ['name' => 'Chair', 'price' => 100], ['name' => 'Lamp', 'price' => 50], ]); $priceRanges = $products->groupBy(function ($product) { return $product['price'] > 100 ? 'expensive' : 'affordable'; });

Sorting Collections

Collections offer multiple sorting methods:

<?php // sort() - Sort by value (ascending) $numbers = collect([5, 3, 1, 4, 2]); $sorted = $numbers->sort(); // [1, 2, 3, 4, 5] // sortDesc() - Sort descending $sorted = $numbers->sortDesc(); // [5, 4, 3, 2, 1] // sortBy() - Sort by key $users = collect([ ['name' => 'John', 'age' => 30], ['name' => 'Jane', 'age' => 25], ['name' => 'Bob', 'age' => 35], ]); $sortedByAge = $users->sortBy('age'); // sortByDesc() - Sort by key descending $sortedByAgeDesc = $users->sortByDesc('age'); // Sort by callback $sortedByNameLength = $users->sortBy(function ($user) { return strlen($user['name']); }); // Multiple sorts $sorted = $users->sortBy('role') ->sortBy('name');

Combining Collections

Merge, concat, and combine collections:

<?php // merge() - Merge arrays (overwrites keys) $collection1 = collect(['a' => 1, 'b' => 2]); $collection2 = collect(['b' => 3, 'c' => 4]); $merged = $collection1->merge($collection2); // ['a' => 1, 'b' => 3, 'c' => 4] // concat() - Append values (keeps all) $collection1 = collect([1, 2, 3]); $collection2 = collect([4, 5, 6]); $concatenated = $collection1->concat($collection2); // [1, 2, 3, 4, 5, 6] // union() - Add items without overwriting $collection1 = collect([1 => 'a', 2 => 'b']); $collection2 = collect([2 => 'c', 3 => 'd']); $union = $collection1->union($collection2); // [1 => 'a', 2 => 'b', 3 => 'd'] // flatten() - Flatten multi-dimensional array $collection = collect([ [1, 2, 3], [4, 5, 6], ]); $flattened = $collection->flatten(); // [1, 2, 3, 4, 5, 6]

Unique and Duplicates

Work with unique values and find duplicates:

<?php // unique() - Remove duplicates $numbers = collect([1, 2, 2, 3, 3, 3, 4]); $unique = $numbers->unique(); // [1, 2, 3, 4] // unique() by key $users = collect([ ['name' => 'John', 'role' => 'admin'], ['name' => 'Jane', 'role' => 'user'], ['name' => 'Bob', 'role' => 'admin'], ]); $uniqueRoles = $users->unique('role'); // duplicates() - Get duplicate values $numbers = collect([1, 2, 2, 3, 3, 3]); $duplicates = $numbers->duplicates(); // [2 => 2, 4 => 3, 5 => 3]

Chunking Collections

Split collections into smaller chunks:

<?php // chunk() - Split into chunks $collection = collect([1, 2, 3, 4, 5, 6, 7]); $chunks = $collection->chunk(3); /* [ [1, 2, 3], [4, 5, 6], [7] ] */ // split() - Split into groups $collection = collect([1, 2, 3, 4, 5]); $groups = $collection->split(3); /* [ [1, 2], [3, 4], [5] ] */ // Practical example: Display in columns $products = Product::all(); $columns = $products->chunk(ceil($products->count() / 3)); foreach ($columns as $column) { echo '<div class="column">'; foreach ($column as $product) { echo '<div>' . $product->name . '</div>'; } echo '</div>'; }

Practical Collection Operations

Real-world examples combining multiple collection methods:

<?php // Example 1: Calculate average order value by customer $orders = collect([ ['customer' => 'John', 'amount' => 100], ['customer' => 'Jane', 'amount' => 150], ['customer' => 'John', 'amount' => 200], ['customer' => 'Jane', 'amount' => 250], ]); $averages = $orders->groupBy('customer') ->map(function ($customerOrders) { return $customerOrders->avg('amount'); }); // ['John' => 150, 'Jane' => 200] // Example 2: Get top 5 most viewed posts $posts = Post::all(); $topPosts = $posts->sortByDesc('views') ->take(5) ->pluck('title', 'id'); // Example 3: Calculate statistics $numbers = collect([10, 20, 30, 40, 50]); $stats = [ 'sum' => $numbers->sum(), 'avg' => $numbers->avg(), 'min' => $numbers->min(), 'max' => $numbers->max(), 'median' => $numbers->median(), ]; // Example 4: Transform and filter user data $users = User::all(); $activeUserEmails = $users ->filter(fn($user) => $user->is_active) ->sortBy('created_at') ->pluck('email') ->unique() ->values();

Lazy Collections

For large datasets, use lazy collections to reduce memory usage:

<?php // Regular collection - loads all into memory $users = User::all(); // Loads 10,000 users // Lazy collection - processes one at a time $users = User::cursor(); // Returns LazyCollection // Process huge dataset efficiently $users->filter(function ($user) { return $user->is_active; })->each(function ($user) { // Process one user at a time Mail::to($user)->send(new Newsletter); }); // Create lazy collection from generator $lazyCollection = LazyCollection::make(function () { $file = fopen('large-file.csv', 'r'); while (($line = fgets($file)) !== false) { yield $line; } fclose($file); }); $lazyCollection->chunk(100) ->each(function ($chunk) { // Process 100 lines at a time });
Tip: Use lazy collections when working with large datasets (10,000+ items) or when reading large files to avoid memory issues.

Higher Order Messages

Collections support "higher order messages" for common operations:

<?php $users = User::all(); // Instead of: $names = $users->map(function ($user) { return $user->name; }); // Use higher order message: $names = $users->map->name; // More examples: $users->each->markAsActive(); $posts->filter->isPublished(); $orders->sum->total; $products->sortBy->price;

Exercise 1: E-commerce Analytics

Use collections to analyze order data and calculate key metrics.

  1. Create collection of orders with: customer_id, product_id, quantity, price
  2. Calculate total revenue: sum of (quantity * price)
  3. Find average order value
  4. Group orders by customer and calculate each customer's total spend
  5. Identify top 3 customers by total spend
  6. Count unique products ordered
  7. Find most popular product (highest total quantity sold)

Exercise 2: Student Grade Processing

Process student grades and generate statistics using collections.

  1. Create collection of students with: name, subject, grade (0-100)
  2. Calculate class average for each subject
  3. Find students with grade >= 90 (A students)
  4. Group students by grade level (A: 90-100, B: 80-89, etc.)
  5. Sort students by grade (highest to lowest)
  6. Get list of students who failed (grade < 60)
  7. Calculate median grade per subject

Exercise 3: Blog Post Dashboard

Build a dashboard with blog post statistics using collections.

  1. Fetch all posts with: title, author_id, category, views, created_at
  2. Group posts by category and count posts per category
  3. Find top 5 most viewed posts
  4. Calculate average views per author
  5. Get posts published in the last 30 days
  6. Create "trending" list: posts with >1000 views in last 7 days
  7. Find authors who published >5 posts this month

Summary

In this lesson, you learned:

  • Creating and working with Laravel Collections
  • Transforming data with map(), filter(), and reduce()
  • Extracting values with pluck()
  • Grouping and sorting collections
  • Combining collections with merge(), concat(), flatten()
  • Finding unique values and duplicates
  • Chunking collections for pagination/processing
  • Real-world collection patterns and use cases
  • Lazy collections for memory efficiency
  • Higher order messages for cleaner code
Next Lesson: We'll explore error handling, logging, and debugging techniques in Laravel.