【问题标题】:Laravel OrderBy relationship countLaravel OrderBy 关系计数
【发布时间】:2014-08-04 04:49:28
【问题描述】:

我正在尝试获得最受欢迎的黑客马拉松,这需要通过相应的黑客马拉松partipants->count() 进行订购。抱歉,如果这有点难以理解。

我有一个格式如下的数据库:

hackathons
    id
    name
    ...

hackathon_user
    hackathon_id
    user_id

users
    id
    name

Hackathon 模型是:

class Hackathon extends \Eloquent {
    protected $fillable = ['name', 'begins', 'ends', 'description'];

    protected $table = 'hackathons';

    public function owner()
    {
        return $this->belongsToMany('User', 'hackathon_owner');
    }

    public function participants()
    {
        return $this->belongsToMany('User');
    }

    public function type()
    {
        return $this->belongsToMany('Type');
    }
}

而HackathonParticipant定义为:

class HackathonParticipant extends \Eloquent {

    protected $fillable = ['hackathon_id', 'user_id'];

    protected $table = 'hackathon_user';

    public function user()
    {
        return $this->belongsTo('User', 'user_id');
    }

    public function hackathon()
    {
        return $this->belongsTo('Hackathon', 'hackathon_id');
    }
}

我试过Hackathon::orderBy(HackathonParticipant::find($this->id)->count(), 'DESC')->take(5)->get());,但我觉得我犯了一个大错误(可能是$this->id),因为它根本不起作用。

我将如何尝试根据最多的相关黑客松参与者获得最受欢迎的黑客松?

【问题讨论】:

    标签: php mysql laravel eloquent


    【解决方案1】:

    我需要对多个计数求和,然后用它来设置顺序。以下查询在 Laravel 8 中对我有用。

    $posts = Post::withCount('comments','likes')->orderBy(\DB::raw('comments_count + likes_count'),'DESC')->get();
    

    【讨论】:

      【解决方案2】:

      你可以使用下面的代码

      Hackathon::withCount('participants')->orderByDesc("participants_count")->paginate(15)
      

      或者如果您甚至想要使用单一方法的 ASC/DESC

      Hackathon::withCount('participants')->orderBy("participants_count", 'asc')->paginate(15)
      

      【讨论】:

        【解决方案3】:

        编辑:如果使用 Laravel 5.2 或更高版本,请使用 kJamesy 的答案。它可能会表现得更好一些,因为它不需要将所有参与者和黑客松加载到内存中,只需将分页的黑客松和这些黑客松的参与者数量加载到内存中。

        您应该可以使用Collection 的sortBy() 和count() 方法相当容易地做到这一点。

        $hackathons = Hackathon::with('participants')->get()->sortBy(function($hackathon)
        {
            return $hackathon->participants->count();
        });
        

        【讨论】:

        • 如何更改升序/降序?
        • sortBy(Closure $callback, $options = SORT_REGULAR, bool $descending = false) 只需将第三个参数设置为 true。
        • sort by 不会在数据库级别执行此操作...因此分页无法正常工作!不过,当您返回全套时很有用..
        • 得到错误 laravel 5.5:调用未定义的方法 Illuminate\Database\Query\Builder
        • 虽然性能很差。因为它将获取查询中每一行的计数。所有计数都应包含在一个查询中以获得快速结果。
        【解决方案4】:

        另一种方法是使用withCount() 方法。

        Hackathon::withCount('participants')
                ->orderBy('participants_count', 'desc')
                ->paginate(50);
        

        参考:https://laravel.com/docs/5.5/eloquent-relationships#querying-relations

        【讨论】:

          【解决方案5】:

          这适用于我在 Laravel 5.3 中,使用你的例子:

          Hackathon::withCount('participants')->orderBy('participants_count', 'desc')->paginate(10); 
          

          这样它在查询中被排序并且分页效果很好。

          【讨论】:

          • 这是一个比公认的更好的答案。
          • 方法 withCount() 被添加到 Laravel 5.2
          • 非常准确和快速的回​​答..谢谢
          • 仅供参考,如果您的关系名称为大写字母,例如maleParticipants,则查询应为thi withCount('maleParticipants')->orderBy('male_participants', 'desc')
          • 谢谢。在 Laravel Backpack 中,我可以使用 $this->crud->query->withCount('contactTags')->orderBy('contact_tags_count', 'desc')。
          【解决方案6】:

          您也可以使用连接运算符。正如 Sabrina 所说,您不能在 db 级别使用 sortby。

          $hackathons = Hackathon::leftJoin('hackathon_user','hackathon.id','=','hackathon_user.hackathon_id')
                     ->selectRaw('hackathon.*, count(hackathon_user.hackathon_id) AS `count`')
                     ->groupBy('hackathon.id')
                     ->orderBy('count','DESC')
                     ->paginate(5);
          

          但是这段代码从数据库中获取所有记录。所以你应该手动分页。

                 $hackathons = Hackathon::leftJoin('hackathon_user','hackathon.id','=','hackathon_user.hackathon_id')
                     ->selectRaw('hackathon.*, count(hackathon_user.hackathon_id) AS `count`')
                     ->groupBy('hackathon.id')
                     ->orderBy('count','DESC')
                     ->skip(0)->take(5)->get();
          

          引用自:https://stackoverflow.com/a/26384024/2186887

          【讨论】:

            【解决方案7】:

            我有类似的问题,并且由于分页而使用 sortBy() 不合适,正如 Sabrina Gelbart 在之前的解决方案中所评论的那样。 所以我使用了 db raw,这里是简化的查询:

            Tag::select( 
            array(
                '*',
                DB::raw('(SELECT count(*) FROM link_tag WHERE tag_id = id) as count_links')) 
            )->with('links')->orderBy('count_links','desc')->paginate(5);   
            

            【讨论】:

            • 我为早期版本的 Laravel 找到的最佳解决方案! (新的可以使用 withCount)不确定它是什么,但我不得不这样做:tag_id = tag.id 而不是 tag_id = id...此外,您可以进一步简化它!而不是做select,你可以做orderByRaw('(SELECT count(*) FROM link_tag WHERE tag_id = tag.id) as count_links') DESC')->paginate(5)。对于那些想知道的人,您不需要->with,除非您正在加载关系
            • 而且..如果您想...Tag::orderByLinkCount()->paginate(5) 然后在您的标签模型中使用您的 orderByRaw 语句创建scopeOrderByLinkCount,也可以在范围内执行此操作
            • 我相信应该是WHERE tag_id = tag.id而不是WHERE tag_id = id
            猜你喜欢
            • 2015-11-21
            • 2017-03-25
            • 2013-08-11
            • 1970-01-01
            • 2020-07-08
            • 2016-09-12
            • 2020-03-25
            • 2018-06-06
            • 1970-01-01
            相关资源
            最近更新 更多