Javi Prieto
Javi Prieto

Reputation: 429

average of counts with Laravel 5

We have two classes: Module and Resource, with a module having many resources:

class Module extends Model {
    public function resources() {
        return $this->hasMany('App\Models\Resource');
    }
} 

and a resource belonging to a Module:

class Resource extends Model {
    public function module() {
        return $this->belongsTo('App\Models\Module');
    }
}

I need to show a list of all the modules with:

  1. The number of resources for each each module
  2. The average of resources per module

The first one is added to the Module model so it can be used with eager loading:

public function resourcesCount() {
    return $this->hasMany('App\Models\Resource')
        ->selectRaw('module_id, count(*) AS aggregate')
        ->groupBy('module_id');
}

However, I can't find an efficient and elegant way to calculate the average of the counts calculated by resourcesCount. I know I could iterate through the results of

$modules = Module::with('resourcesCount')->get(); 

and do it manually, but I feel there's something better out there.

EDIT: forgot to say that I modified the accessor for the resourcesCountAttribute:

public function getResourcesCountAttribute() {
    if (!$this->relationLoaded('resourcesCount')) 
        $this->load('resourcesCount');

    $related = $this->getRelation('resourcesCount');
    return ($related) ? (int) $related->aggregate : 0;
}

So I can use 'resourcesCount' (See my response), rather than having to use 'resourcesCount.aggregate'.

Upvotes: 1

Views: 1820

Answers (2)

Javi Prieto
Javi Prieto

Reputation: 429

I found out an acceptable way to do so, using the collection's methods.

// Returns an elloquent collection
$modules = Module::with('resourcesCount')->get(); 

// counts sums divided by the number of 
$avgResources = $modules->sum('resourcesCount') / $modules->count();

Upvotes: 1

Matt Wohler
Matt Wohler

Reputation: 171

The only way would be to do it through iteration or in a separate DB::select() statement, relying on things like GROUP BY and AVERAGE().

Upvotes: 0

Related Questions