Laravel:如何获得嵌套的hasMany关系的平均值(hasManyThrough)

Luu*_*gen 7 php mysql relationship laravel eloquent

我有三张桌子:

products:   id|name|description|slug|category_id|...
reviews:    id|product_id|review_text|name|email|...
review_rows id|review_id|criteria|rating
Run Code Online (Sandbox Code Playgroud)

审查表存储审阅文本,审阅的编写者并具有外部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        |
----------------------------------------
Run Code Online (Sandbox Code Playgroud)

审核行使用review_id外键链接到审阅表.我已经建立了这样的模型关系:

Product   -> hasMany   -> Review
Review    -> belongsTo -> Product
Review    -> hasMany   -> ReviewRow
ReviewRow -> belongsTo -> Review
Run Code Online (Sandbox Code Playgroud)

现在,我想在我的类别和产品页面上显示产品的平均评分.我怎样才能做到这一点?

我需要对每次审核的所有评论进行求和并对其进行平均,然后对每个评论的所有评分进行求和并平均,最后得出该产品的总评分.这可能是通过Eloquent还是我需要不同的解决方案或不同的数据库设计/结构?

提前致谢!

Jar*_*zyk 16

你需要这样的东西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;
}
Run Code Online (Sandbox Code Playgroud)

然后就这么简单:

// 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
Run Code Online (Sandbox Code Playgroud)