I am working on Laravel query that shall count the latest month data and also group by week, for the last 3 months. I have tried to fix that in a few ways but still it’s exceeds my memory limit and load very slow. Bellow is the current code that I am using to get the final results – but same problem is also here.
Any idea how to optimize the counting and grouping the data?
JavaScript
x
$data['pois']['total'] = PoiLocation::whereYear('created_at', Carbon::now()->year)
->whereMonth('created_at', Carbon::now()->month)
->count();
$pois = PoiLocation::where('created_at', '>', (new Carbon)->subMonths(3))
->get()
->sortBy('created_at')
->groupBy(function ($collection) {
return Carbon::parse($collection->created_at)->isoWeek();
});
if ($pois->count()) {
foreach ($pois as $item => $value) {
$data['pois']['weeks'][$item] = $value->count();
}
} else {
$data['pois']['weeks'] = [];
}
if ($data['pois']['weeks']) {
$data['pois']['high'] = max($data['pois']['weeks']);
} else {
$data['pots']['high'] = 1;
}
JavaScript
protected $fillable = [
'store_id', 'name', 'address1', 'address2', 'city','state','zip_code', 'dma_desc', 'country', 'lat' ,'lon', 'target', 'is_verified', 'polygons', 'external_id', 'brandID', 'companyID'
];
protected $dates = ['created_at', 'updated_at'];
public $timestamps = true;
Advertisement
Answer
You could use LazyCollections
. This should heavily reduce your memory usage.
JavaScript
$pois = PoiLocation::query()
->where('created_at', '>', Carbon::now()->subMonths(3))
->orderBy('created_at') // sort in DB instead of wasting more memory doing the sorting.
->cursor() // don't load every model in memory
->remember() // don't repeat the query (if this line wasn't here, the query would be made 3 times. 1- $poi->all(), 2- ($poi->max() !== null) 3- $poi->max() )
->groupBy(function (Poilocation $poiLocation) { // param here is not a collection, it's a Poilocation. Type hint is completely optional
return $poiLocation->created_at->isoWeek(); // $poiLocation->created_at should already be a Carbon instance because of Eloquent magic.
})
->map->count();
$data['pois']['weeks'] = $poi->all();
$data['pois']['high'] = ($poi->max() !== null) ? $poi->max() : 1;
This also simplifies your logic.
$poi->all()
will either return an array, empty or not, with the keys.$poi->max()
will return themax()
of the collection. If the collection is empty, it will returnnull
. A simple ternary operator takes care of that part of your logic as well.