相关模型的 Laravel 计数列

Posted

技术标签:

【中文标题】相关模型的 Laravel 计数列【英文标题】:Laravel count column of related model 【发布时间】:2014-11-24 02:07:29 【问题描述】:

我想统计某个Script 中来自ScripRating 的赞成票和反对票的数量。

Script.php

public function ratings()

    return $this->hasMany('ScriptRating');

ScriptRating.php:

public function script()

    return $this->belongsTo('Script');

script_rating 数据库表:

id (primary, increments)
script_id(integer)
rating(integer) <-- Can be either 1 (upvote) or -1 (downvote)

检索脚本并显示评分:

$script = Script::where('title', '=', $title)->get();
 $script->ratings 

这很好用,它返回一个数组:["id":1,"script_id":1,"rating":1]。但在这一点上,我被困住了。我如何计算某个脚本的赞成票和反对票总数?

我还有一个小问题,让我感到困惑。这与上面的代码相同:

$script = Script::where('title', '=', $title)->with('ratings')->get();
 $script->ratings 

这两种方法有什么区别,我应该使用哪一种?

提前致谢!

编辑

我做了三个范围:

public function scopeTotalRating($query, $scriptId) 
    return $query->where('script_id', $scriptId)->get()->sum('rating');


public function scopeThumbsUp($query, $scriptId) 
    return $query->where('script_id', $scriptId)->having('rating', '=', 1)->get()->sum('rating');


public function scopeThumbsDown($query, $scriptId) 
    return $query->where('script_id', $scriptId)->having('rating', '=', -1)->get()->sum('rating');

并显示如下:

 ScriptRating::thumbsUp($script->id) 

【问题讨论】:

【参考方案1】:

你可以使用

$script-&gt;ratings-&gt;count()

这将显示一个脚本的总评分数。

但是,您感兴趣的是将评级分组为upvotesdownvotes,因此您需要通过group by 子句查询您的关系。

Script::where('title', '=', $title)->with([
    'ratings' => function($query) 
        $query->groupBy('rating');
    )
])->get();

我认为返回的集合现在应该按1-1 分组。让我知道结果!

编辑:您还可以在此处查看有关查询关系的文档:

http://laravel.com/docs/4.2/eloquent#querying-relations

编辑回复:

不使用 group by 的最简单方法是单独查询:

$script = Script::where('title', $title)->first();

if ($script) 
    $upvotes = ScriptRating::where('script_id', $script->id)->having('rating', '>', 0)->get()->count();

    $downvotes = ScriptRating::where('script_id', $script->id)->having('rating', '<', 0)->get()->count();

您提到的脚本之间的差异也称为eager loadinglazy loading。当您在查询中指定 -&gt;with() 时,这称为预加载。如果你不这样做,查询将在你指定$script-&gt;ratings时运行

更多关于急切/延迟加载的信息:

http://laravel.com/docs/4.2/eloquent#eager-loading

编辑其他回复:

如果您想收集有评级的脚本,您可以使用-&gt;whereHas('ratings') 函数。您还可以通过执行 if 语句来检查具有评级的脚本是否存在:

if ($script->ratings->count() > 0)  
    // The script has ratings
 else 
    // The script does not have ratings

如果您不想重复此代码,您可以随时使用以下代码在 Script.php 模型中添加一个函数:

public function hasRatings()

    return $this->ratings->count() > 0;

那么你可以这样做:

if ($script-&gt;hasRatings())

【讨论】:

感谢您的评论。我尝试了上面的代码,但我不知道如何使用它。如何检索反对/赞成票?另外,你知道我第二个问题的答案吗? 谢谢!你可以在我的第一篇文章中看到我做了什么。我现在遇到的唯一问题是这个错误:Object of class Illuminate\Database\Eloquent\Builder could not be converted to string 当脚本没有任何评级时会发生这种情况。你知道如何解决这个问题吗?【参考方案2】:

您可以将这 2 个函数添加到 Script 模型类中:

public function ratingsSumRelation()

    return $this->hasOne('ScriptRating')->selectRaw('script_id, sum(rating) as sum_all')
        ->groupBy('script_id');


public function getRatingSumAttribute()


    return $this->ratingsSumRelation ?
        $this->ratingsSumRelation->sum_all: 0;

现在显示总和:

 $script->rating_sum 

【讨论】:

我确实做到了,但它给了我 SQL 语法错误。另外,如果我理解这一点,这将返回反对票和赞成票的总和。我需要这些数据,但我也需要单独的赞成票和反对票。请原谅我的英语不好。 @JasonK 有一个错字。现在看,如果你有错误,你应该总是提供完整的错误信息 是的,我已经注意到 't' 不见了。语法错误:near '*) as sum from script_rating where script_rating.script_id = ? group by ' at line 1 (SQL: select script_id, sum(*) as sum from script_rating where script_rating.script_id = 1 group by script_id limit 1) (View: C:\xampp\htdocs\laravel\laravel\app\views\script.blade.php) @JasonK 我已经更改了答案 - 将 as sum`` 更改为 as sum_all 并在第二个函数中相同 仍然出现语法错误:) as sum_all from script_rating where script_rating.script_id = ? group b' at line 1 (SQL: select script_id, sum() as sum_all from script_rating where script_rating.script_id = 1 group by script_id limit 1

以上是关于相关模型的 Laravel 计数列的主要内容,如果未能解决你的问题,请参考以下文章

Laravel orderByRaw 计数列不存在

Laravel 查询,其中列值大于相关模型列值的总和

Laravel HasMany 查询最新入口并返回相关模型

Laravel Eloquent - 从相关模型中检索特定列

Laravel 关系多对多按外键计数相关数据

Laravel 5.2 orderBy与ofCount的关系导致SQL错误,因为尝试获取列而不是计数失败