CakePHP 模型:可包含的 COUNT(*)

Posted

技术标签:

【中文标题】CakePHP 模型:可包含的 COUNT(*)【英文标题】:CakePHP Model: COUNT(*) in Containable 【发布时间】:2011-01-19 11:14:12 【问题描述】:

我有一个 Cakephp 1.3 应用程序,非常喜欢使用 Containable behavior 获取数据。

假设我的帖子与评论是一对多的关系。我使用 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'),
        );

不起作用,结果集为每个 Post 包含一个空的 Comment 数组,除了最后一个,它包含 count 字段,但包含所有 cmets 的数量而不仅仅是所属的。

我的另一个猜测是

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

但这会导致错误,因为 hasMany 关系是独立查询的,所以 Answer 表不在 Post 条目的查询中。 如何计算帖子的评论数?

【问题讨论】:

你有没有找到没有 counterCache 的解决方案? 【参考方案1】:

嗯,最好的方法是在posts 表中设置一个名为comment_count 的字段,并将这个键添加到评论模型$belongsTo Post 数组中:

'counterCache' => true

每当 cmets 发生任何事情时,相关帖子中的 comment_count 字段都会更新(实际上,它每次都会重新计算,而不仅仅是添加或删除)。

更好,因为当您为用户获取数据时,它的速度更快,甚至不会触及 cmets 表。由于您使用的是 Containable 行为,我猜您正在寻找速度和轻量级。

【讨论】:

这是个好主意,但它不能解决更复杂的查询的问题,在这些查询中保持与行相关联的计数不起作用(例如,报告系统中选择了某些条件)用户)。有没有其他方法可以使用containable 来获得计数?【参考方案2】:

我也有同样的问题。 PawelMysior 给出的答案非常好,并导致了解决方案。

我在 CakePHP Book:3.7.4.1.1 counterCache - Cache your count() 中找到了更多细节。这很有帮助,但仍然有点模糊。为了其他人,我想提供一些进一步的细节。

我有两个表:Post 和 Image。当我将图片添加到帖子时,我想跟踪每个帖子有多少张图片显示在帖子索引列表中,而无需在 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 更新为正确的数量。

我希望这些额外信息对某人有所帮助。

【讨论】:

我注意到有人对此投了反对票,但没有就原因发表评论。也许这与这个问题/答案是 8 岁有关?无论哪种方式,没有评论的反对票都是不好的形式。

以上是关于CakePHP 模型:可包含的 COUNT(*)的主要内容,如果未能解决你的问题,请参考以下文章

Cakephp 分页按计算字段排序( COUNT )

CakePHP 模型关联深层模型包含

Cakephp 2.x 在同一字段上查找同时具有 DISTINCT 和 COUNT 的查询

带有无用条目的 CakePhp 可包含查询

Cakephp - 条件保存

CakePHP 多模型关联