2011-04-18 73 views
4

我正在使用CakePHP作为CMS/Web服务来为iPhone应用程序供电。我想知道如何去订购我的.find()方法,以便我可以通过一些外部模型的“计数”来排序?如何在CakePHP中通过“投票”进行排序?

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

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

我怎样才能改变排序依据条款,使其通过返回25个最流行的视频?

+0

你基本上需要在票COUNT(*)表? – Dunhamzzz 2011-04-18 12:53:32

+1

你可以发布表格之间的关系吗?即我认为一个视频有很多票和一票投票属于一个视频。 – Belinda 2011-04-18 13:04:39

+0

@Belinda绝对。投票属于视频,视频hasMany Vote。 – 2011-04-18 13:50:20

回答

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或使用蛋糕递归功能轻松修复。鉴于上述情况,我会写:

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

我想你可以从这里看到如何访问您的视图中的数据。

Hoppy Coding!

UPDATE: 如果你只需要视频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 
       ) 
     ) 
) 
+0

不是简单易用,只是一个普通的SQL? xD – dynamic 2011-04-18 15:00:29

+0

您不受CakePHP框架的限制。您可以确定编写一个自定义连接查询,它将模拟相同的结果。这也是有效的。但是,问题是如何使用.find函数来获取结果。这是如何做到这一点。如果问题的措辞不同,我会提供该解决方案。 – 2011-04-18 20:25:46

+1

请记住@ yes123,它并不总是关于什么是最简单的,而是关于什么是正确的。 ;) – 2011-04-18 20:40:09

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)) 
+0

由于投票计数是来自另一个表的投票的count(),所以您的查询会在'order clause''中产生一个错误'SQL错误:1054:未知列'vote_count'。 – 2011-04-18 20:31:48

+0

不,没有,请阅读我在回答中提到的counterCache上的文章 – Leo 2011-04-19 09:15:07

+0

是的。请记住,我不认为你的解决方案是一个糟糕的实施。但被问到的问题是“我怎样才能按外部模型计数”。不是,“我应该如何更改我的模式和代码来实现counterCache”。 OP表示视频表中没有计数器列。您的解决方案需要将一个新列添加到'video'表中。因此,根据现有模式以及所问的问题,尝试使用counterCache时会发生SQL错误,除非对模式进行了修改。这是我所知道的技术性。 – 2011-04-19 17:28:42

相关问题