Laravel: how to get average on nested hasMany relationships (hasManyThrough)

前端 未结 2 1666
广开言路
广开言路 2020-12-30 07:52

I have three tables:

products:   id|name|description|slug|category_id|...
reviews:    id|product_id|review_text|name|email|...
review_rows id|review_id|crite         


        
相关标签:
2条回答
  • 2020-12-30 08:19

    Maybe you can try with Eloquent relationships and a little help from php function array_reduce

    //model/Reviews.php
    public function sum() {
        return array_reduce($this->hasMany('ReviewRows')->lists('rating'), "sumItems");  
    }
    
    public function sumItems ($carry, $item) {
        $carry += $item;
        return $carry;
    }
    

    Or with Eloquent RAW querys like:

    //model/Reviews.php
    public function avg() {
       $result = $this->hasMany('ReviewRows')
       ->select(DB::raw('avg(rating) average'))
       ->first();
       return $result->average;
    }
    
    0 讨论(0)
  • 2020-12-30 08:41

    You need something like this http://softonsofa.com/tweaking-eloquent-relations-how-to-get-hasmany-relation-count-efficiently/ only slightly adjusted to match your needs:

    public function reviewRows()
    {
        return $this->hasManyThrough('ReviewRow', 'Review');
    }
    
    public function avgRating()
    {
        return $this->reviewRows()
          ->selectRaw('avg(rating) as aggregate, product_id')
          ->groupBy('product_id');
    }
    
    public function getAvgRatingAttribute()
    {
        if ( ! array_key_exists('avgRating', $this->relations)) {
           $this->load('avgRating');
        }
    
        $relation = $this->getRelation('avgRating')->first();
    
        return ($relation) ? $relation->aggregate : null;
    }
    

    Then as simple as this:

    // eager loading
    $products = Product::with('avgRating')->get();
    $products->first()->avgRating; // '82.200' | null
    
    // lazy loading via dynamic property
    $product = Product::first()
    $product->avgRating; // '82.200' | null
    
    0 讨论(0)
提交回复
热议问题