web-dev-qa-db-fra.com

Laravel OrderBy nombre de relations

J'essaie d'obtenir les hackathons les plus populaires, qui nécessitent d'être commandés par la fonction partipants->count() du hackathon respectif. Désolé si c'est un peu difficile à comprendre.

J'ai une base de données au format suivant:

hackathons
    id
    name
    ...

hackathon_user
    hackathon_id
    user_id

users
    id
    name

Le modèle Hackathon est:

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');
    }
}

Et HackathonParticipant est défini comme:

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');
    }
}

J'ai essayé Hackathon::orderBy(HackathonParticipant::find($this->id)->count(), 'DESC')->take(5)->get()); mais je sens que j'ai commis une grosse erreur (peut-être le $ this-> id), car cela ne fonctionne pas du tout.

Comment pourrais-je essayer d'obtenir les hackathons les plus populaires basés sur le plus grand nombre de hackathonParticipants associés?

27
Joe Torraca

Vous devriez pouvoir utiliser les méthodes sortBy() et count() de Collection pour le faire assez facilement.

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

Cela fonctionne pour moi dans Laravel 5.3, en utilisant votre exemple:

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

De cette façon, il est ordonné sur la requête et la pagination fonctionne bien.

83
kJamesy

Une autre approche peut être d'utiliser la méthode withCount()

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

Réf: https://laravel.com/docs/5.5/eloquent-relationships#querying-relations

15
tisuchi

J'avais un problème similaire et utiliser sortBy () n'est pas approprié à cause de la pagination, exactement comme Sabrina Gelbart l'a commenté dans la solution précédente .

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);   
12
Johnyz

Vous pouvez également utiliser l'opérateur de jointure. Comme Sabrina l'a dit, vous ne pouvez pas utiliser Sortby au niveau de la base de données.

$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);

Mais ce code prend tous les enregistrements de la base de données. Donc, vous devriez paginer manuellement.

       $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();

Référé de: https://stackoverflow.com/a/26384024/2186887

0