← BACK
Laravel / Collections

Dynamic Date Grouping in Laravel Collections Using Closures in groupBy()

Punyapal Shah • • 1 min read
edit this tip →

Pass a closure to Laravel Collection's groupBy() method to group models and arrays dynamically by day, week, month, or quarter.

Laravel's Collection::groupBy() method is commonly used with a simple string key (such as ->groupBy('status')).

However, groupBy() also accepts a closure that receives each item in the collection and returns the dynamic group key. This is especially useful for aggregating records into date intervals such as weeks, quarters, or formatted periods for reporting dashboards.

Grouping Records by Dynamic Time Periods

use App\Models\Order;
use Carbon\Carbon;
use Illuminate\Support\Collection;

$orders = Order::query()
    ->where('created_at', '>=', now()->subYear())
    ->get();

$interval = request('interval', 'week'); // 'day', 'week', 'month', 'quarter', 'year'

$groupedOrders = $orders->groupBy(function (Order $order) use ($interval): string {
    $date = $order->created_at;

    return match ($interval) {
        'day' => $date->format('D d M Y'),
        // Output: "Sun 01 Jan 2026"

        'week' => $date->copy()->startOfWeek()->format('d M Y') . ' - ' . $date->copy()->endOfWeek()->format('d M Y'),
        // Output: "01 Jan 2026 - 07 Jan 2026"

        'month' => $date->format('M Y'),
        // Output: "Jan 2026"

        'quarter' => $date->copy()->firstOfQuarter()->format('M') . ' - ' . $date->copy()->lastOfQuarter()->format('M Y'),
        // Output: "Jan - Mar 2026"

        'year' => $date->format('Y'),
        // Output: "2026"
    };
});

Structure of the Resulting Collection

The returned collection uses the formatted date strings as keys, with each entry containing the subset of matching models:

// Example quarter grouping:
[
    "Jan - Mar 2026" => Collection [ Order #101, Order #102 ],
    "Oct - Dec 2025" => Collection [ Order #89, Order #90 ],
]

Aggregating Data per Period

Once grouped, you can chain standard collection operations like map() or sum() to build dashboard statistics:

$revenueByQuarter = $groupedOrders->map(function (Collection $orders): float {
    return $orders->sum('total_amount');
});

Summary

  • Pass a closure to Collection::groupBy() for dynamic, computed grouping criteria.
  • Pair with Carbon's period helpers (startOfWeek(), firstOfQuarter()) to group data into reporting intervals.
  • Chain map() and sum() on grouped collections to calculate interval metrics effortlessly.

Related Tips

View all tips →
Laravel Collections

Group Consecutive Items with chunkBy()

Use chunkBy() to split a Collection whenever the resolved value changes, without manually comparing items with the previous chunk.

READ >
Laravel Collections

Simplify Collection Operations with Higher-Order Messages

Laravel Collections support higher-order messages through dynamic properties, allowing operations like each, map, filter, and groupBy to work directly with an item's property or method without writing boilerplate callbacks.

READ >

// Got a tip in mind? Contributions are always welcome