laravel 4 关系 - 如何显示用户投票的前 5 名记录排名

Posted

技术标签:

【中文标题】laravel 4 关系 - 如何显示用户投票的前 5 名记录排名【英文标题】:laravel 4 relations - how display a top-5 ranking of records voted by users 【发布时间】:2015-02-23 12:59:15 【问题描述】:

我正在创建一个新闻源系统,您可以轻松猜到,这超出了我的技能范围。 请善待我,让我走上正轨或提供一些我可以继续下去的东西。

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

数据透视表user_attitudes(Model Userattitude)的相关列是 id, item_type, item_id, importance, attitude, 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。

该表服务于许多模型 - 上面的示例包括两个 - 只是为了更好地了解我所拥有的。

我需要什么:

    我希望打印前 5 个事件的排名(以及后来的其他模型)。我希望能够使用两种计算总分的方法:

    通过计算实际值(0,1,2,3) 将任何大于 0 的值计为 1 分。

    我想生成按此标准过滤事件的视图:

    至少有一个用户将重要性设置为“0”(我需要它来将事件标记为不可信) 尚未评级的事件 与上述相反 - 由至少一位用户评分的事件 按对其赋予任何重要性的用户数量列出的事件

    这很容易,但我仍然不知道如何实现它。与上述 #2 相同的过滤器,但与特定用户决策相关

    列出 5 或 10 个尚未被用户评分的事件(随机或最新) 也许这样的事情会是一个答案:

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

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

型号:

Event1(表“事件”):

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

用户:(表 'users' - 标准用户表)

public function importances()

    return $this->hasMany('Userattitude', 'creator_id');

在模型Userattitude(不同于User,表名'user_attitudes')

public function events()

    return $this->morphTo('item')->where('item_type', 'event');




public function event()

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

回复@lucas 的问题:

问题 1.

表名“项目”让我感到困惑,因为在我的项目中,“项目”是事件(模型 Event1)、参与者(模型实体)和其他对象。 在我掌握您提供的知识之前,我们可以坚持我的命名吗? 它还包含名为 attitudes 的列,用于将特定项目列入黑名单。 例如,用户可以对“实体”类型的项目(多个事件的可能参与者)进行两次投票: - 由用户设置的 importance(我们现在正在这样做,可用的值是 0,1,2,3) - 根据用户对(可能的值(-1, 0, 1)的态度 这样的解决方案允许我计算每个项目的业力。例如 -1 x 3 = -3(最坏的业力值),而 1 x 2 = 2(中等正业力)。

因此,我无法通过 users 方法使用查询。对我来说还是太混乱了,抱歉。我们偏离了我最初的心理形象太远了。 考虑这个查询:

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

如果在 Event1 我声明

    public function users()

    return $this->morphToMany('User', 'item', null, null, 'creator_id');

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

我收到此错误:

[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) [] []

如果我将方法定义更改为

    public function users()

    return $this->morphToMany('Userattitude', 'item', null, null, 'creator_id');

注意:用户态度是模型(表名是'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]: 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 = @9876544 .iduser_attitudes.Userattitudes_type = Event1) >= 1) [] []

可能的解决方案: 名为“items”的“user_attitudes”表别名。 我可以创建一个具有所需名称的视图。 我做到了,但现在查询没有结果。

问题 2

我应该将 creator_id 重命名为 user_id - 还是保留两列并在其中保留重复信息? creator_id 遵循约定,我用它来创建记录……如何解决这个难题?

问题 3。

据我了解,如果我想获得前 5 名事件的用户相关列表, 我需要在代码中添加另一行,将搜索范围缩小到特定登录用户创建的记录:

Auth::user()->id)

代码如下所示: 重要性为 0 的所有内容

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

)->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 importance')
            ->groupBy('entities.id')
            ->orderBy('importance', 'desc')
            ->take(6)
            ->get(); 

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

$e->importance or '-'

但是我如何显示替代查询的计数:来自另一列的值的总和,命名为姿态,可以在这个单独的查询中计算:

换句话说,在我的@foreach 循环中,我需要同时显示 $e->importance 和计算得到的 SUM(user_attitudes.attitude) AS karma,现在可以通过此查询接收:

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

我的解决方案是在“实体”表中创建一些额外的列: - 业力_负 - 业力正面 每次有人投票时存储/更新总票数。

【问题讨论】:

【参考方案1】:

首先,让我们谈谈设置。我不完全确定你的工作方式和是否有效,但我在我的测试实例上创建了它并且它有效,所以我建议你相应地改变你的:

数据库

事件

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

id(主键) 姓名(或类似名称) 等

用户

我不确定在您的示例中是否是 Userattitude,但我不这么认为...

id(主键) 电子邮件 (?) 等

项目

这是最重要的。数据透视表。名称可以不同,但​​为了保持简单并遵循约定,它应该是多态关系的复数(在您的情况下为 item =&gt; items

id(实际上甚至没有必要,但我把它留在了那里) item_type item_id 重要性 creator_id(考虑将其更改为user_id。这将简化关系声明)

型号

我认为您必须再次阅读docs。你声明了几个奇怪的关系。我是这样做的:

事件1

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

class Event1 extends Eloquent 

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

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

用户

class User extends Eloquent implements UserInterface, RemindableInterface 

    // ... default laravel stuff ...

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

查询

好的,现在我们可以开始了。第一个附加信息。我尽可能使用 Eloquent 关系。在所有查询中,使用join() 会更慢,因为某些事情(例如计算或计算最大值)必须在查询之后在 php 中完成。 mysql 在这些方面做得很好(在性能方面也是如此)。

总价值前 5 名

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

票数超过 0 的前 5 名

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

重要性为 0 的全部

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

全部无票

$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(items.id) AS count')
                ->groupBy('events.id')
                ->orderBy('count', 'desc')
                ->get();

最新 5 个无票

如果你使用 Eloquents 时间戳created_at

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

如果你不是(按最大 id 排序):

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

随机 5 无票

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

我没有故意对查询添加任何解释。如果您想了解更多有关特定内容或需要帮助的信息,请发表评论

【讨论】:

如果Userattitutes 是连接usersevents 的表/模型,那么您根本不需要模型。 item_type 的值应为 event(或您指定为 morphClass 的任何值) 这太棒了!谢谢!我需要消化这一点并进行实验以产生更好的问题。但现在......我不太确定如何实现你的一些代码。为了获得帮助,我需要将我的项目公开。我不愿意这样做。可以在与您的私人对话中提供更多数据吗?稍后我将完善我最初的问题,使其更容易被其他人理解。 不,我不会给你写邮件的。此外,您可能不应该公开您的地址。不过,我对 *** 聊天持开放态度。他们不是私人的,但我想我无论如何都可以帮助你。大约 5 小时后您在线吗? (世界标准时间下午 1 点) 是的,我在线。我正在尝试使用户关系正常工作(问题 1) - 我刚刚将表 'user_attitudes' 克隆到 'items' 中 I created a chat【参考方案2】:

问题 4:已解决!(感谢 @lukasgeiter)

如果您希望显示项目的排名并将结果限制在数据透视表中定义的特定标签,这就是解决方案:

$events = Event1(表名 = 'events')

例如,标签是 war:在表中定义 事件标签

事件性质定义为

id = '1' 是 name = 'wars' id = '2' 是 name = 'conflicts' 数据透视表,分配多个标签event_eventtags 它们被定义为 id = '4'

event_eventtags 的示例记录:

id - event_id - eventtag_id

1 - 45 - 1

2 - 45 - 2

简单的英语:Event1 #45 被标记为战争(#1)和冲突(#2)

现在为了打印 10 场战争的列表,您应该以这种方式定义您的查询:

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

user_attitudes 是原始问题中描述的投票系统的一部分。您可以删除它并通过其他方法对事件进行排序。

【讨论】:

以上是关于laravel 4 关系 - 如何显示用户投票的前 5 名记录排名的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 5:用户关注其他用户(如twitter) - 如何设置关系

Laravel 模型必须返回一个关系实例

Laravel API - 通过 o2m 关系显示单个文件

如何在 Laravel 中对所有行使用多态关系?

如何使用 laravel+VueJS 以一对一的关系获取数据

雄辩的关系,模型的链接(Laravel 5.4)