Laravel: как получить среднее значение для вложенных отношений hasMany (hasManyThrough)

У меня три таблицы:

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

в обзорной таблице хранится текст обзора, автор обзора и имеет внешний ключ product_id. В таблице review_rows хранятся оценки для разных критериев, таких как:

 ---------------------------------------- | id | criteria | rating | review_id | ---------------------------------------- | 1 | price | 9 | 12 | ---------------------------------------- | 2 | service | 8 | 12 | ---------------------------------------- | 3 | price | 6 | 54 | ---------------------------------------- | 4 | service | 10 | 54 | ---------------------------------------- 

строки обзора связаны с таблицей обзора с внешним ключом review_id. Я установил свои модельные отношения следующим образом:

 Product -> hasMany -> Review Review -> belongsTo -> Product Review -> hasMany -> ReviewRow ReviewRow -> belongsTo -> Review 

Теперь я хотел бы отобразить средний рейтинг продукта на моей странице категории и продукта. Как я могу это достичь?

Мне нужно суммировать и усреднять все рецензии за просмотр, а затем суммировать и усреднять все из них для каждого обзора, чтобы получить общий рейтинг для этого продукта. Возможно ли это через Eloquent или мне нужно другое решение или другой дизайн / структура базы данных?

Заранее спасибо!

Вам нужно что-то подобное http://softonsofa.com/tweaking-eloquent-relations-how-to-get-hasmany-relation-count-efficiently/, только слегка скорректированное в соответствии с вашими потребностями:

 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; } 

Тогда просто:

 // 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 

Может быть, вы можете попробовать с отношениями Eloquent и немного помочь от php-функции 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; } 

Или с запросами Eloquent RAW, такими как:

 //model/Reviews.php public function avg() { $result = $this->hasMany('ReviewRows') ->select(DB::raw('avg(rating) average')) ->first(); return $result->average; }