简体   繁体   中英

How can I order by 'votes' in CakePHP?

I'm using CakePHP for a CMS/web service to power an iPhone app. I'm wondering how I would go about ordering my .find() method so that I can order by the "count" of some external models?

For example: A video object is associated with votes . So there are multiple Vote rows (with user_id and video_id) for a single Video row.

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

How can I change the orderby clause so that it returns the 25 most popular videos by votes ?

Dunhamzzz's comment of using a counterCache ( +1 ) is the best approach. After you have set this up everytime someone adds a vote a field called vote_count will be incremented in the video table for the associated video. You can then simply sort by this field.

So in your Vote Model

var $belongsTo = array('Video' => array('counterCache' =>true));

And create the vote_count field in your Video table

Then sort

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

Let's assume you have the following tables:

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

The SQL you are trying to write is something like:

    SELECT 
      count(id), 
      video_id 
   FROM votes 
   GROUP BY video_id 
   ORDER BY count(id) DESC 
   LIMIT 25;

The problem is, it will not return the video name. This is easily remedied with a JOIN or by using cakes recursive feature. Given the above, I would write the following:

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

When you get the data back, you will also get the Video information (due to the recursive option being set to 1) as long as your relationships in the models are set up correctly.

For example, the data will look something like:

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

I think you can see from here how to access the data in your view.

Hoppy Coding!

UPDATE: If you only need the video id, you can do something like:

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

This will return:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM