return 关系总和聚合的最佳方法 属性

Best way to return the sum aggregation of a relations property

我有一个简单的结构,其中 post 有很多选票。投票的 "value" 属性 为 1 或 -1

在阅读所有 post 时,我希望将每个 post 的总和 select 转化为 post 级别的自定义 属性。目前我这样做

    $posts = Post::where('published_at', '<=', $date)
        ->orderBy('published_at', 'desc')
        ->simplePaginate(20);

    $posts->each(function($post) {
        $post->overallRating = $post->getRating();
    });

这是完全有效的,但我认为对数据库进行 20 次查询以读取评级并不是很好。有没有办法在 posts 的实际获取中简化这一点?

public function getRating()
{
    return $this->votes->sum('value');
}

试试这个:

$posts = Post::where('published_at', '<=', $date)
        ->orderBy('published_at', 'desc')
        ->with(['votes' => function($query) {
            $query->sum('value');
        }])->simplePaginate(20);

如果您想保留包含在分页结果中的选票,那么我建议添加 with('votes'),这样它们至少可以提前加载,即

$posts = Post::with('votes')
    ->where('published_at', '<=', $date)
    ->orderBy('published_at', 'desc')
    ->simplePaginate(20);

但是,如果您 want/aren 不在意获得选票,而只想获得每个 post 的评分,则可以将以下范围添加到 Post型号:

public function scopeWithRating(Builder $query)
{
    if (is_null($query->getQuery()->columns)) {
        $query->select([$query->getQuery()->from . '.*']);
    }

    $query->selectSub(
        $this->votes()->getRelationExistenceQuery(
            $this->votes()->getRelated()->newQuery(), $query, new Expression('sum(value)')
        )->toBase(),
        'rating'
    );
}

然后:

$posts = Post::withRating()
    ->where('published_at', '<=', $date)
    ->orderBy('published_at', 'desc')
    ->simplePaginate(20);

希望对您有所帮助!