2010-02-22 84 views
11

我有一個CakePHP 1.3應用程序,並且非常喜歡Containable behavior來獲取數據。CakePHP模型:COUNT(*)in Containable

讓我們假設我有帖子與評論的一對多關係。我使用Containable查詢(分頁)所有帖子和所有者註釋的列表。但我只對每個帖子有多少評論感興趣。我沒有找到任何方式來實現這個查詢與含有不含所有行的評論。我試過了:

$this->paginate=array(
      'fields' => 'Post.title, Post.created', 
      'contain' => array('Comment'=>'COUNT(*) AS count'), 
     ); 

結果'模型'註釋'與模型沒有關聯'計數''的錯誤信息。

$this->paginate=array(
      'fields' => array('Post.title, Post.created'), 
      'contain' => array('Comment'=>array('fields'=>'COUNT(*) AS count'), 
     ); 

不起作用,每個帖子的結果集包含一個空的評論陣列除了最後一個,它包含了數場,但具有所有評論不只是屬於那些數量。

我其他的猜測是

$this->paginate=array(
      'fields' => 'Post.title, Post.created, COUNT(Comment.id)', 
      'contain' => array('Comment'=>array('fields'=>''), 
     ); 

但這會導致一個錯誤,因爲的hasMany關係是獨立詢問,所以回答表是不是在查詢後條目。 如何計算郵寄的評論數量?

回答

11

好,要做到這一點的最好辦法是建立一個名爲comment_count場在posts表,這個鍵添加到註釋模型$屬於關聯帖子陣列:

'counterCache' => true

每次什麼東西會隨着評論的發生,相關文章中的comment_count字段將被更新(實際上,它每次都會重新計算,而不僅僅是添加或刪除)。

它更好,因爲當你爲用戶提取數據時,它的速度更快,甚至不會觸及評論表。由於您使用的是可容忍的行爲,我想速度和輕量級就是您要找的。

+3

這是一個不錯的主意,但它不能解決更復雜的查詢問題,即保持與行關聯的計數不起作用(例如用戶選擇某些條件的報告系統)。有沒有其他方法可以使用容易獲得計數? – Zxaos 2011-09-15 18:11:05

6

我有同樣的問題。 PawelMysior給出的答案很好,並導致瞭解決方案。

我在CakePHP書中找到了更多的細節:3.7.4.1.1 counterCache - Cache your count()。這很有幫助,但仍有點模糊。爲了其他人的緣故,我想提供一些進一步的細節。

我有兩個表:Post和Image。當我向帖子添加圖片時,我想跟蹤每篇帖子在帖子索引列表中顯示的圖片數量,而無需在圖片表上運行額外的計數查詢。

CREATE TABLE posts 
(
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, 
user_id INTEGER UNSIGNED NOT NULL, 
title VARCHAR(255), 
body TEXT, 
created DATETIME, 
modified DATETIME, 
image_count INTEGER UNSIGNED, 
PRIMARY KEY (id) 
) ENGINE=InnoDB; 

CREATE TABLE images 
(
id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT, 
post_id INTEGER UNSIGNED NOT NULL, 
filename VARCHAR(255), 
created DATETIME, 
modified DATETIME, 
PRIMARY KEY (id) 
) ENGINE=InnoDB; 

注意,image_count雲在posts表。 images表中沒有什麼特別的。

class Post extends AppModel 
{ 
    var $name = 'Memory'; 
    var $hasMany = array(
     'Image' => array(
      'className' => 'Image', 
      'foreignKey' => 'post_id', 
      'dependent' => false 
     ) 
    ); 
} 

class Image extends AppModel 
{ 
    var $name = 'Image'; 
    var $belongsTo = array(
     'Post' => array(
      'className' => 'Post', 
      'foreignKey' => 'post_id', 
      'counterCache' => true 
     ) 
    ); 
} 

注意counterCache被添加到Image模型。 Post模型沒有什麼特別的。

$this->Post->Behaviors->attach('Containable'); 
$post = $this->Post->find('all', array(
    'conditions' => array('user_id' => 7), 
    'order' => array('Post.created DESC'), 
    'contain' => array(
     'Post' => array(
      'User' => array('first_name', 'last_name') 
     ) 
    ) 
)); 

現在,當我們做一個find沒有必要做任何特殊找到計數,因爲它會自動在Post結果的字段。請注意下面的image_count

Array 
(
[Post] => Array 
     (
      [0] => Array 
       (
        [id] => 14 
        [user_id] => 7 
        [title] => Another great post 
        [body] => Lorem ipsum... 
        [created] => 2011-10-26 11:45:05 
        [modified] => 2011-10-26 11:45:05 
        [image_count] => 21 
        [User] => Array 
        (
         [first_name] => John 
         [last_name] => Doe 
        ) 
       ) 
     ) 
) 

有一點需要注意,如果你添加counterCache到現有的數據庫結構,在Post計數爲零,直到另一個Image加入。此時,CakePHP將執行實際計數並將image_count更新爲正確的數量。

我希望這個額外的信息對某人有幫助。