Модель 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
до нужной суммы.
Я надеюсь, что эта дополнительная информация поможет кому-то.