Multiple groupBy on Laravel Collection

30,253

Solution 1

The solution in https://stackoverflow.com/a/30469061/221745 can be improved on I think. The key is to remember that a grouped by collection is a collection of collections. Therefore, the following will work:

<?php

$recs = new \Illuminate\Database\Eloquent\Collection($query);
$grouped = $recs->groupBy('performed_at_year_month')->transform(function($item, $k) {
    return $item->groupBy('performer_id');
});

Where $grouped contains your final result

Solution 2

Laravel now (since 5.5.29) supports multi-level nested grouping, as per https://christoph-rumpel.com/2018/1/groupby-multiple-levels-in-laravel

$query = Activity::all()->groupBy(['performed_at_year_month', 'performer_id'])->toJson();

Solution 3

Instead of passing a string key, you may pass a callback. The callback should return the value you wish to key the group by:

$collection->groupBy(function($item, $key){
            return $item["key-1"]."-".$item["key-2"];
        });

Reference:- https://laravel.com/docs/5.7/collections#method-groupby

Solution 4

You can try chaining them, however I am not sure it will get you the results you want. May want to check to be sure

$query = Activity::all()->groupBy('performed_at_year_month')->groupBy('performer_id')->toJson();

I just checked this and you are correct, it's not preserving keys, although I think I can guess why. If a key happens to be the same, things will get overwritten. It could also be difficult to determine which key is what and overall feels a little "hacky" where there is likely a much better solution.

However, I think I've figured out how to do this.

$query = Activity::all();
$activities = new \Illuminate\Database\Eloquent\Collection($query);
$activities = $activities->groupBy('performed_at_year_month')->toArray() + $activities->groupBy('performer_id')->toArray();
echo json_encode($activities);
Share:
30,253

Related videos on Youtube

Michalis Antoniou
Author by

Michalis Antoniou

Updated on February 20, 2021

Comments

  • Michalis Antoniou
    Michalis Antoniou about 3 years

    I am trying to group a collection by two clauses in Laravel 5, but it only groups it by the first one. Can someone please help me out? Here's my code.

    $query = Activity::all()->groupBy('performed_at_year_month', 'performer_id')->toJson();
    
  • Michalis Antoniou
    Michalis Antoniou almost 9 years
    Thanks! This does return the data grouped correctly, but it does not include the keys (performed_at_year_month, performer_id) on the json string. Can you recommend a fix for that?
  • Clifton H.
    Clifton H. almost 6 years
    Pass true as the second parameter for groupBy($string, $preserveKeys). $activities->groupBy('performed_at_year_month', true)