phplaravelsumgroupinglaravel-collection

Group and sum Laravel collection data by date value of a datetime column


I have a variable called $data which holds a collection that looks something like this:

[
    "date" => "2017-10-07 10:00:00"
    "usage" => 0.423
    "costs" => 1.212
],
[
    "date" => "2017-10-07 11:00:00"
    "usage" => 0.786
    "costs" => 1.564
],
[
    "date" => "2017-10-07 12:00:00"
    "usage" => 0.542
    "costs" => 1.545
]

(The data can be every hour for up to 2 months, for readability I chose to include only 3 hours in this example)

As you can see, it's all per hour (which is also data I need for a different part in the code) I would like a separate collection per day. Is there an easy way to group by date('Ymd') and sum usage and costs? I should also mention that not all items in the collection have all indexes. Some don't have usage, some don't have costs. All do have date however.


Solution

  • You could possibly achieve this with something like this:

    $collection = collect([
        [
            "date" => "2017-10-07 10:00:00",
            "usage" => 0.423,
            "costs" => 1.212
        ],
        [
            "date" => "2017-10-07 11:00:00",
            "usage" => 0.786,
            "costs" => 1.564
        ],
        [
            "date" => "2017-10-07 12:00:00",
            "usage" => 0.542,
            "costs" => 1.545
        ],
        [
            "date" => "2017-10-08 10:00:00",
            "costs" => 1.1
        ],
        [
            "date" => "2017-10-08 11:00:00",
            "usage" => 0.786,
        ],
        [
            "date" => "2017-10-08 12:00:00",
            "costs" => 1.567
        ]
    ]); 
    
    
    return $collection->groupBy(function($row) {
        return Carbon\Carbon::parse($row['date'])->format('Y-m-d'); 
    })->map(function($value, $key) {
        return [
            'usage' => $value->sum('usage'), 
            'costs' => $value->sum('costs')
        ];
    });
    

    The output of the above will be this:

    Collection {#267 ▼
      #items: array:2 [▼
        "2017-10-07" => array:2 [▶]
        "2017-10-08" => array:2 [▼
          "usage" => 0.786
          "costs" => 2.667
        ]
      ]
    }
    

    As you can see from the above, some of the items do not have usage or costs. It will still work.

    Here's also an example you can play with.