laravel 4 relations - how display a top-5 ranking of records voted by users

后端 未结 2 1387
挽巷
挽巷 2021-01-19 15:43

I am creating a system of newsfeed, and as you can easily guess, it is beyond my skills. Please be kind to put me on the right track or provide something I can go on with.<

相关标签:
2条回答
  • 2021-01-19 16:05

    First, let's talk about the setup. I wasn't entirely sure how and if your's works but I created this on my testing instance and it worked, so I recommend you change yours accordingly:

    Database

    events

    That's a simple one (and you probably already have it like this

    • id (primary key)
    • name (or something like that)
    • etc

    users

    I'm not sure if in your example that is Userattitude but I don't think so...

    • id (primary key)
    • email (?)
    • etc

    items

    This is the important one. The pivot table. The name can be different but to keep it simple and follow conventions it should be the plural of the polymorphic relation (in your case item => items)

    • id (actually not even necessary, but I left it in there)
    • item_type
    • item_id
    • importance
    • creator_id (consider changing that to user_id. This would simplify the relationship declaration)


    Models

    I think you have to read the docs again. You had several weird relations declared. Here's how I did it:

    Event1

    By default Laravel uses the classname (get_class($object)) as value for the ..._type column in the database. To change that you need to define $morphClass in your models.

    class Event1 extends Eloquent {
    
        protected $table = 'events';
        protected $morphClass = 'event';
    
        public function users()
        {
            return $this->morphToMany('User', 'item', null, null, 'creator_id');
        }
    }
    

    User

    class User extends Eloquent implements UserInterface, RemindableInterface {
    
        // ... default laravel stuff ...
    
        public function events(){
            return $this->morphedByMany('Event1', 'item', null, null, 'creator_id');
        }
    }
    


    Queries

    Alright now we can get started. First one additional information. I used Eloquent relations whenever possible. In all the queries a join() is made it would be slower to use relations because certain things (like counting or calculating the maximum) would have to be done in PHP after the query. And MySQL does a pretty good job (also performance wise) at those things.

    Top 5 by total value

    $events = Event1::leftJoin('items', function($q){
                        $q->on('item_id', '=', 'events.id');
                        $q->where('item_type', '=', 'event');
                    })
                    ->selectRaw('events.*, SUM(items.importance) AS importance')
                    ->groupBy('events.id')
                    ->orderBy('importance', 'desc')
                    ->take(5)
                    ->get();
    

    Top 5 by number of votes over 0

    $events = Event1::leftJoin('items', function($q){
                        $q->on('item_id', '=', 'events.id');
                        $q->where('item_type', '=', 'event');
                        $q->where('importance', '>', 0);
                    })
                    ->selectRaw('events.*, COUNT(items.id) AS importance')
                    ->groupBy('events.id')
                    ->orderBy('importance', 'desc')
                    ->take(5)
                    ->get();
    

    All with importance 0

    $events = Event1::whereHas('users', function($q){
        $q->where('importance', 0);
    })->get();
    

    All without any votes

    $events = Event1::has('users', '<', 1)->get();
    

    All with 1+ votes

    $events = Event1::has('users')->get();
    

    All ordered by number of votes

    $events = Event1::leftJoin('items', function($q){
                        $q->on('item_id', '=', 'events.id');
                        $q->where('item_type', '=', 'event');
                    })
                    ->selectRaw('events.*, COUNT(items.id) AS count')
                    ->groupBy('events.id')
                    ->orderBy('count', 'desc')
                    ->get();
    

    Newest 5 without votes

    If you are using Eloquents timestamps created_at:

    $events = Event1::has('users', '<', 1)->latest()->take(5)->get();
    

    If you're not (order by greatest id):

    $events = Event1::has('users', '<', 1)->latest('id')->take(5)->get();
    

    Random 5 without votes

    $events = Event1::has('users', '<', 1)->orderByRaw('RAND()')->take(5)->get();
    

    I did not add any explanations to the queries on purpose. If you want to know more about something specific or need help, please write a comment

    0 讨论(0)
  • 2021-01-19 16:21

    PROBLEM 4: SOLVED! (credit to @lukasgeiter)

    If you wish to display a ranking of items and limit the results to a particular tag defined in a pivot table, this is the solution:

    $events = Event1 (table name = 'events')

    For example, the tag would be war: defined in table eventtags

    Event nature are defined as

    id = '1' is name = 'wars' id = '2' is name = 'conflicts' pivot table, which assigns multiple tags: event_eventtags they are defined as id = '4'

    Example records for event_eventtags:

    id - event_id - eventtag_id

    1 - 45 - 1

    2 - 45 - 2

    Plain English: the Event1 #45 is tagged as war(#1) and conflict(#2)

    Now in order to print a list of 10 wars you should define your query in this way:

    $events= Entity::join('event_eventtags', function($q){
             $q->on('entity_id', '=', 'entities.id');
             $q->where('entitycapacitytypes_id', '=', 1);
         })->leftJoin('user_attitudes', function($q){
             $q->on('item_id', '=', 'entities.id');
             $q->where('item_type', '=', 'entity');
        })
        ->selectRaw('entities.*, SUM(user_attitudes.importance) AS importance')
        ->groupBy('entities.id')
        ->orderBy('importance', 'desc')
        ->take(10)
        ->get();
    

    The user_attitudes is part of voting system described in the original question. You can remove it and sort events by another method.

    0 讨论(0)
提交回复
热议问题