如何在CakePHP中按'votes'排序?

4

我正在使用CakePHP作为CMS / Web服务来支持iPhone应用程序。 我想知道如何通过“count”某些外部模型的数量对我的.find()方法进行排序?

例如:一个视频对象与投票相关联。 因此,对于单个Video行,有多个Vote行(具有user_id和video_id)。

$videos = $this->Video->find('list', array( <<orderby stuff>> ));

如何更改orderby子句以返回25个最受欢迎的视频,按投票排序?


你是否基本上需要在投票表中使用COUNT(*)? - Dunhamzzz
1
你能发布一下表之间的关系吗?例如,我假设一个视频有多个投票,而一个投票属于一个视频。 - Belinda
@Belinda 当然可以。投票属于视频,视频拥有多个投票。 - Jamie Chapman
3
你考虑过使用计数缓存吗? - Dunhamzzz
我认为下面的评论将涵盖检索您要查找的数据的两个选项。如果您需要视频的名称和ID或仅ID,请愉快地编码! - Chuck Burgess
2个回答

1
Dunhamzzz提出的使用counterCache(+1)的评论是最佳方法。设置完成后,每当有人添加投票时,与视频相关的视频表中的一个名为vote_count的字段将会增加。然后,您可以通过该字段进行简单的排序。
因此,在您的投票模型中,
var $belongsTo = array('Video' => array('counterCache' =>true));

在你的视频表中创建vote_count字段

然后排序

$videos = $this->Video->find('list', array( 'order' => array('vote_count DESC'), 'limit'=>25 ))

不是的,阅读我回答中提到的有关counterCache的文章。 - Leo
是的,它会。请记住,我并不是在争论你的解决方案是否是一个糟糕的实现。但是问题是“如何按外部模型的计数排序”。而不是“我应该如何更改我的架构和代码来实现counterCache”。OP表明视频表中没有计数器列。你的解决方案需要向video表添加一个新列。因此,基于现有的架构和提出的问题,除非对架构进行修改,否则在尝试使用counterCache时将发生SQL错误。我知道这是一个技术性的问题。 - Chuck Burgess
是的,我提到要添加一个video_count字段,这样就不会因为按照我的答案而出现错误。 - Leo
1
@Leo:在一个设计良好的真实数据库引擎中,这并不是非常重要的。如果可能的话,应该避免使用像vote_count这样的列。 - Adam Robinson
@Leo:这是完全错误的。你不应该存储任何可以计算的东西。如果有什么意外导致vote_count没有被更新,会发生什么?它会立即(并永久地)变得无效。-1 - Ken White
显示剩余3条评论

1

假设您有以下表:

CREATE TABLE `videos` (
  `id` char(36) NOT NULL,
  `name` varchar(50) NOT NULL,
  PRIMARY KEY (`id`)
)

CREATE TABLE `votes` (
  `id` char(36) NOT NULL,
  `video_id` char(36) NOT NULL,
  `user_id` char(36) NOT NULL,
  PRIMARY KEY (`id`)
);

你正在尝试编写的 SQL 语句大致如下:
    SELECT 
      count(id), 
      video_id 
   FROM votes 
   GROUP BY video_id 
   ORDER BY count(id) DESC 
   LIMIT 25;

问题是,它不会返回视频名称。这很容易通过JOIN或使用cake的递归特性来解决。鉴于上述情况,我会编写以下代码:
$this->Vote->recursive = 1;
$vote_info = $this->Vote->find('all', 
   array(
      'fields' => array('count(Vote.id)','Video.name'), 
      'group' => array('video_id'), 
      'order' => array('count(Vote.id) DESC'), 
      'limit' => 25, 
   )
);

当您获取数据时,只要您的模型关系设置正确(递归选项设置为1),您还将获得视频信息。

例如,数据将类似于:

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [count(`Vote`.`id`)] => 3
                )
            [Video] => Array
                (
                    [name] => Dumb and Dumber
                )
        )
    [1] => Array
        (
            [0] => Array
                (
                    [count(`Vote`.`id`)] => 1
                )
            [Video] => Array
                (
                    [name] => Lord of the Rings
                )
        )
    [2] => Array
        (
            [0] => Array
                (
                    [count(`Vote`.`id`)] => 1
                )
            [Video] => Array
                (
                    [name] => Just Do It
                )
        )
)

我认为你可以从这里看到如何访问视图中的数据。
愉快编程!
更新: 如果你只需要视频的id,你可以这样做:
$this->Vote->recursive = 0;
$votes = $this->Vote->find('all', 
   array(
      'fields' => array('count(Vote.id) as count', 'Vote.video_id'), 
      'order' => array('count(Vote.id) DESC'),
      'group' => array('Vote.video_id'),
      'limit' => 25,
   )
);

这将返回:

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [count] => 3
                )
            [Vote] => Array
                (
                    [video_id] => 4dac4de7-4f80-48c1-8a02-83b4dfa458e5
                )
        )
    [1] => Array
        (
            [0] => Array
                (
                    [count] => 1
                )
            [Vote] => Array
                (
                    [video_id] => 4dac4ddc-712c-4795-8d9a-83b4dfa458e5
                )
        )
    [2] => Array
        (
            [0] => Array
                (
                    [count] => 1
                )
            [Vote] => Array
                (
                    [video_id] => 4dac4df0-382c-4bb5-a5ee-83b4dfa458e5
                )
        )
)

使用纯SQL不是更容易吗?xD - dynamic
你并不受限于CakePHP框架。你当然可以编写自定义连接查询,以模拟相同的结果。这也是有效的。然而,问题是如何使用.find函数来获取结果。以下是如何做到这一点。如果问题措辞不同,我会提供另一个解决方案。 - Chuck Burgess
1
记住 @yes123,这并不总是关于什么最容易,而是关于什么是正确的。;) - Chuck Burgess
唯一的问题是,如果一个视频没有投票,那么如何让查询也包括这些呢?(基本上是左连接) - Jamie Chapman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接