laravel 4关系 - 如何显示用户投票记录的前五名排名 [英] laravel 4 relations - how display a top-5 ranking of records voted by users

查看:675
本文介绍了laravel 4关系 - 如何显示用户投票记录的前五名排名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个新闻源系统,你可以很容易猜到,这是超出我的技能。
请把我放在正确的轨道上,或提供一些可以继续的东西。



我有几百个事件(型号名称为Event1,table 'events')
我还有一个数据透视表,用户可以在其中指定任何事件的重要性(值0,1,2,3)



相关列的数据透视表user_attitudes(Model Userattitude)是
id item_type item_id 重要性态度 creator_id
一个例子三个记录是:



456 - 事件 - 678 - 2 - 4



457 - 事件 - 690 - 3 - 15



458 - 事件 - 690 - 1 - 4



459 - 参与者 - 45 - 1 - 4



普通英语:事件#690的总计重要性为4,而事件#678为2。
因此,在我的排名中,#690的事件应该列为第一。



只是看到更大的图片:用户#4也将参与者#45评为重要性= 1。



表服务许多模型 - 上面的例子包括两个 - 只是为了给出更好的我的图像。



我需要什么:




  1. 我希望打印排名前五的事件楷模)。我希望能够使用两种计算总分的方法:




    • 通过计算实际值(0,1,2,3 )

    • 通过将0以上任何值计为1分。


  2. 根据这个条件生成过滤事件的视图:




    • 至少有一个用户将重要性设置为0(我需要它来标记事件不可信赖)

    • 尚未评级的事件

    • 上述的反向 - 至少由一个用户评级的事件

    • 由分配给其重要性的用户数列出的事件


  3. 这很简单,但是我仍然不知道如何使它发生。与上述#2相同的过滤器,但与特定用户决定相关




    • 列表5或10尚未被用户评估的事件(随机或最新)
      可能是这样的一个答案:



    $ q-> where('creator_id','=',Auth :: user() - > id);


相关代码:
由于我没有真正把握合并关系,我可能无法显示提供帮助所需的一切 - 在评论中要求更多的代码。



模型:



Event1(表'events'):

  public function importances()
{
return $ this-> morphMany('Userattitude','item');
}

public function user_importance($ user)
{
return $ this-> morphMany('Userattitude','item') - > where( 'creator_id',($ user?$ user-> id:NULL)) - > first();
}

用户:(表'用户' - 标准用户表) / strong>

  public function importances()
{
return $ this-> hasMany(' Userattitude','creator_id');
}

在模型中 Userattitude (不同于用户,表name'user_attitudes')

  public function events()
{
return $ this-> morphTo ('item') - > where('item_type','event');
}



public function event()

{
return $ this-> belongsTo('Event1' ,'item_id');
}

回答问题答案:



问题1。



表名'items'让我感到困惑,因为我的项目'项目'是事件模型Event1),参与者(模型实体)等对象。
我可以坚持我的命名,直到我掌握了你所提供的知识吗?
它还包含名为态度的列,用于列出特定项目。
例如,一个类型实体(多个事件的可能参与者)的项目可以由用户双重投票:
- 由用户设置的重要性(我们现在可以使用的值是0,1,2,3)
- 由用户的态度(可能的值(-1,0,1)
这样的解决方案允许我计算每个项目的因果关系,例如-1 x 3 = -3(最差的可能的业力值),而1 x 2 = 2(中等的正因果)。



因此,我无法使用用户方法的查询,对我来说还是太混乱了,对不起,我们偏离了我原来的心理形象太远了
考虑这个查询:

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

如果在Event1中,我声明

  public function users()
{
return $ this-> morphToMany('User','item',null,null,'creator_id');
}

注意:用户是标准的用户表,其中用户名,密码和电子邮件存储



我收到此错误:

  [2014-12 -28 05:02:48] production.ERROR:FATAL DATABASE ERROR:500 = SQLSTATE [42S02]:未找到基表或视图:1146表'niepoz_niepozwalam.items'不存在(SQL:select * from`Events` where(select count(*)from`users` inner join`items` on`users`.`id` =`items`.`creator_id`其中`items`.`item_id` =`Events`.`id`和` item`.`item_type` = Event1)> = 1)[] [] 

如果我更改方法定义为

  public function users()
{
return $ this-> morphToMany 'Userattitude','item',null,null,'creator_id');
}

注意:Useratitude是我所存储的模型(表名为'user_attitudes')用户判断。



我收到相同的错误。



如果我将方法更改为

  public function users()
{
return $ this-> morphToMany 'User','Userattitudes',null,null,'creator_id');
}

我得到这个:



[2014-12-28 05:08:28] production.ERROR:FATAL DATABASE ERROR:500 = SQLSTATE [42S22]:未找到列:1054'where子句'中的未知列'user_attitudes.Userattitudes_id'(SQL:选择*从事件其中(从用户选择count(*) inner join user_attitudes 用户 id = user_attitudes creator_id 其中 user_attitudes Userattitudes_id = 事件 id user_attitudes Userattitudes_type = Event1)> = 1)[] []



可能的解决方案:
user_attitudes表名称为items的表别名。
我可以创建一个带有必需名称的视图。
我这样做,但现在查询不产生结果。



问题2



我应该将creator_id重命名为user_id吗?还是保留这两个列并保留重复的信息? creator_id遵循约定,我用它创建记录...如何解决这个dillema?



问题3。



据我所知,如果我想获得前5名活动的USER-RELATED列表,
我需要向代码添加另一行,缩小搜索范围对于特定登录用户创建的记录:

  Auth :: user() - > id)

代码如下所示:
全部重要0

  $ events = Event1 :: whereHas('users',function($ q){
$ q-> where(' important',0);
$ q-> where('creator_id','=',Auth :: user() - > id);
pre>

}) - > get();



对?



问题5:



好的,我现在可以输出这样的查询:

  $ rank_entities = Entity :: leftJoin('user_attitudes',function($ q){
$ q-> ; on('entity_id','=','entities.id');
$ q-> where('item_type','=','entity');
})
- > selectRaw('entities。*,SUM(user_attitudes.importance)AS important')
- > groupBy('entities.id')
- > orderBy('important','desc')
- > take(6)
- > get();

在foreach循环中,我可以使用此代码显示总重要性数:

  {{$ e->重要性或' - '}} 

但是我可以显示一个替代查询的计数:来自另一列的值的SUM,名为attitude,可以在此SEPARATE查询中计算:


换句话说,在我的@foreach循环中,我需要显示$ e->重要性和计算的 SUM(user_attitudes.attitude)作为业务,现在可以收到这个查询:

  $ rank_entities = Entity :: leftJoin('userattitudes',function($ q){
$ q-> on('entity_id','=','entities.id');
$ q-> where('item_type','=','entity');
})
- > selectRaw('entities。*,SUM(userattitudes.karma)AS karma')
- > groupBy('entities.id')
- > orde rBy('karma','desc')
- > take(5)
- > get();

我的解决方案是在实体表中创建一些额外的列:
- karma_negative
- karma_positive
存储/更新每次有人投票时的总投票数。

解决方案

首先,让我们来谈一下设置。我不完全确定如何和如果你的工作,但我在我的测试实例上创建了它,它的工作,所以我建议你相应地更改你的



数据库



事件



这是一个简单的(你可能已经有这样的




  • id(主键)

  • 名称(或类似的东西)




用户



我不知道在你的例子中是否是code> Userattitude 但我不这么认为...




  • id(主键)

  • 电子邮件(?)






这是重要的一个数据透视表。名称可以不同,但​​是要保持简单,遵循约定,它应该是多态关系的复数(在你的案例 item => items




  • id(实际上甚至不必要,我留在那里)

  • item_type

  • item_id

  • 重要性

  • creator_id(请考虑将其更改为 USER_ID 。这将简化关系声明)






模型



我想你必须阅读 docs 。你们宣布了几个奇怪的关系。以下是我做的:



Event1



默认情况下,Laravel使用类名( get_class($ object))作为数据库中 ..._类型列的值。要更改,您需要在模型中定义 $ morphClass

  Event1类扩展Eloquent {

protected $ table ='events';
protected $ morphClass ='event';

public function users()
{
return $ this-> morphToMany('User','item',null,null,'creator_id');
}
}



用户



  class用户扩展Eloquent实现UserInterface,RemindableInterface {

// ...默认laravel内容...

public function events(){
return $ this-> morphedByMany('Event1','item',null,null,'creator_id');
}
}




查询



现在我们可以开始了。第一个附加信息。我尽可能地使用雄辩的关系。在所有查询中,一个 join()被使用,因为某些事情(如计数或计算最大值)必须在PHP之后完成查询。而在这些事情上,MySQL做得很好(也是性能明智的)。



按总价值排列的前5名

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



超过0的票数前5名



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



全部重要0



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



所有没有任何投票



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



所有与+1票



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



所有按票数排序



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



最新5票没有投票



如果你正在使用口述时间戳 created_at

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

如果你不是(以最大的身份排序):

  $ events = Event1 :: have('users','<',1) - > latest('id') - > take(5) - >得到(); 



无选票随机5



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

我没有为查询添加任何解释。如果您想了解更多有关某些特定内容或需要帮助的信息,请写下评论


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.

I have several hundred events (model name is Event1, table 'events') I also have a pivot table in which users can assign any event's importance (values 0,1,2,3)

The relevant columns of the pivot table user_attitudes (Model Userattitude) are id, item_type, item_id, importance, attitude, creator_id An example three record are:

456 - event - 678 - 2 - 4

457 - event - 690 - 3 - 15

458 - event - 690 - 1 - 4

459 - participant - 45 - 1 - 4

Plain English: Total aggregated importance of the event #690 is '4', while the event #678 is '2'. Therefore in my ranking the event #690 should be listed as first.

Just to see the bigger pic: the user #4 also rated participant # 45 as importance = 1.

The table services many models - the above example include two - just to give a better image of what I have.

WHAT I NEED:

  1. I wish to print a ranking of top 5 events (and later other models). I wish to be able to use two methods of calculating the total score:

    • by counting the actual value (0,1,2,3)
    • by counting any value above 0 as 1 point.
  2. I want to generate views which filter events by this criteria:

    • at least one user set the importance to '0' (I need it to flag an event as untrustworthy)
    • events which has not been rated yet
    • reverse of the above - events which are rated by at least one user
    • events listed by number of users who assigned any importance to it
  3. This is easy, but still I have no idea how to make it happen. The same filters as the above #2, but related to a particular user decisions:

    • list 5 or 10 events (random or newest) which has not yet been rated by the user maybe something like this would be an answer:

    $q->where('creator_id', '=', Auth::user()->id);

Relevant code: As I don't really grasp the merged relations, I might fail to show everything needed to provide help - ask for more code in comments.

Models:

Event1 (table 'events'):

public function importances()
{
    return $this->morphMany('Userattitude', 'item');
}

public function user_importance($user)
{
    return $this->morphMany('Userattitude', 'item')->where('creator_id', ($user ? $user->id : NULL))->first();
}

User: (table 'users' - standard user table)

public function importances()
{
    return $this->hasMany('Userattitude', 'creator_id');
}

In model Userattitude (different from User, table name 'user_attitudes')

public function events()
{
    return $this->morphTo('item')->where('item_type', 'event');
}



public function event()

    {
        return $this->belongsTo ('Event1', 'item_id');
    }

PROBLEMS IN REPLY TO @lucas answer:

PROBLEM 1.

table name 'items' keeps me confused as in my project 'items' are events (model Event1), the participants (model Entity) and other objects. Can we stick to my naming until I get hold of the knowledge you are providing? it also contains column named attitudes, which is used for blacklisting particular items. For instance, an item of type 'entity' (possible participant of multiple events) can be voted by user two-wise: - by importance set by an user (we are doing this now, values available to use are 0,1,2,3) - by attitude of an user toward (possible value (-1, 0, 1) Such solution allows me to compute karma of each item. For instance -1 x 3 = -3 (worst possible karma value), while 1 x 2 = 2 (medium positive karma).

In consequence I am unable to use queries with the users method. It is still too confusing to me, sorry. We diverted too far from my original mental image. Consider this query:

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

If in Event1 I declare

    public function users()
{
    return $this->morphToMany('User', 'item', null, null, 'creator_id');
}

Note: User is the standard users table, where username, password and email are stored

I get this error:

[2014-12-28 05:02:48] production.ERROR: FATAL DATABASE ERROR: 500 = SQLSTATE[42S02]: Base table or view not found: 1146 Table 'niepoz_niepozwalam.items' doesn't exist (SQL: select * from `Events` where (select count(*) from `users` inner join `items` on `users`.`id` = `items`.`creator_id` where `items`.`item_id` = `Events`.`id` and `items`.`item_type` = Event1) >= 1) [] []

if I change the method definition to

    public function users()
{
    return $this->morphToMany('Userattitude', 'item', null, null, 'creator_id');
}

Note: Userattitude is model (table name is 'user_attitudes') where i store user judgments. This table contains columns 'importance' and 'attitude'.

I get the same error.

If I change the method to

    public function users()
{
    return $this->morphToMany('User', 'Userattitudes', null, null, 'creator_id');
}

I get this:

[2014-12-28 05:08:28] production.ERROR: FATAL DATABASE ERROR: 500 = SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user_attitudes.Userattitudes_id' in 'where clause' (SQL: select * from Events where (select count(*) from users inner join user_attitudes on users.id = user_attitudes.creator_id where user_attitudes.Userattitudes_id = Events.id and user_attitudes.Userattitudes_type = Event1) >= 1) [] []

Possible solution: the 'user_attitudes' table alias with name 'items'. I could create a view with the required name. I did it, but now the query produces no results.

PROBLEM 2

should I rename creator_id into user_id - or keep both columns and keep duplicated information in them? The creator_id follows conventions and I use it to create records... how to resolve this dillema?

PROBLEM 3.

As far as I understand, if I want to get a USER-RELATED list of top-5 events, I need to ad another line to the code, which narrows search scope to records created by a particular logged in user:

Auth::user()->id)

The code would look like this: All with importance 0

$events = Event1::whereHas('users', function($q){
$q->where('importance', 0);
$q->where('creator_id', '=', Auth::user()->id);

})->get();

right?

PROBLEM 5:

Ok, I am now able to output a query like these:

$rank_entities = Entity::leftJoin('user_attitudes', function($q){
                $q->on('entity_id', '=', 'entities.id');
                $q->where('item_type', '=', 'entity');
            })
            ->selectRaw('entities.*, SUM(user_attitudes.importance) AS importance')
            ->groupBy('entities.id')
            ->orderBy('importance', 'desc')
            ->take(6)
            ->get(); 

and in the foreach loop I can display the total importance count with this code:

{{$e->importance or '-'}}

But How I could display count of an alternative query: SUM of values from another column, named attitude, which can be computed in this SEPARATE query:

In other words, in my @foreach loop I need to display both $e->importance and a computed SUM(user_attitudes.attitude) AS karma, which for now can be received with this query:

$rank_entities = Entity::leftJoin('userattitudes', function($q){
                $q->on('entity_id', '=', 'entities.id');
                $q->where('item_type', '=', 'entity');
            })
            ->selectRaw('entities.*, SUM(userattitudes.karma) AS karma')
            ->groupBy('entities.id')
            ->orderBy('karma', 'desc')
            ->take(5)
            ->get(); 

My solution would be to create some extra columns in the 'entities' table: - karma_negative - karma_positive to store/update total amount of votes each time someone is voting.

解决方案

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

这篇关于laravel 4关系 - 如何显示用户投票记录的前五名排名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆