Модель CakePHP: COUNT (*) в контейнере

У меня есть приложение CakePHP 1.3 и действительно наслаждаюсь Контейнерное поведение для получения данных.

Предположим, что у меня есть сообщения в отношениях "один ко многим" с комментариями. Я использую Containable для запроса (для разбивки на страницы) списка всех сообщений и принадлежащих комментариев. Но меня интересует только то, сколько комментариев у каждой Почты. Я не нашел никакого способа достичь этого запроса с помощью сдерживаемого без извлечения всех строк комментариев. Я пробовал:

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

приводит к "Модельному комментарию", не связанному с сообщением об ошибке "Count".

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

не работает, набор результатов содержит для каждого столбца пустой массив комментариев, за исключением последнего, где он содержит поле count, но имеет количество всех комментариев не только принадлежащих им.

Мое другое предположение было

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

но это приводит к ошибке, так как отношения hasMany запрашиваются независимо, поэтому таблица ответов не находится в запросе записей Post. Как я могу подсчитать количество комментариев в сообщении?

Ответ 1

Ну, лучший способ сделать это - настроить поле под названием comment_count в таблице posts и добавить этот ключ к модели Comment $arrayTo Post:

'counterCache' => true

Каждый раз, когда что-либо будет происходить с комментариями, поле comment_count в соответствующем сообщении будет обновляться (на самом деле он пересчитывается каждый раз, а не просто добавляет или удаляет).

Это лучше, потому что, когда вы извлекаете данные для пользователя, его путь быстрее и даже не касается таблицы комментариев. Поскольку вы используете Containable поведение, я думаю, что скорость и легкий вес - это то, что вы ищете.

Ответ 2

У меня был тот же вопрос. Ответ, который дал PawelMysior, был отличным и привел к решению.

Я нашел в книге CakePHP более подробную информацию: 3.7.4.1.1 counterCache - Cache your count(). Это было полезно, но все еще немного расплывчато. Ради других, я хочу представить некоторые дополнительные подробности.

У меня есть две таблицы: Post и Image. Когда я добавлял изображение в сообщение, я хочу отслеживать, сколько изображений, которое каждое сообщение имело для отображения в списке индекса Post, без необходимости запуска дополнительного счетчика в таблице изображений.

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 до нужной суммы.

Я надеюсь, что эта дополнительная информация поможет кому-то.