我有三张桌子:
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实现的,还是需要不同的解决方案或不同的数据库设计/结构?
提前致谢!
答案 0 :(得分:13)
您需要稍微调整一下 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
答案 1 :(得分:2)
也许你可以尝试使用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;
}
答案 2 :(得分:0)
见https://github.com/faustbrian/laravel-commentable
public function comments(): MorphMany
{
return $this->morphMany($this->commentableModel(), 'commentable');
}
public function avgRating()
{
return $this->comments()->avg("rating");
}
$products = \App\Models\Products::with(
[
"comments" => function ($q) {
$q->with(["children" => function ($qch) {
$qch->take(2);
}
])->withCount("children")->where("parent_id", '=', null);
},]
)->take(5)->get();
foreach ($products as &$product) {
$product["avgRating"] = $product->avgRating();
}
dd($products);