Проблемы с фильтрацией ресурсов (больше 2000шт.)
Стоит задача отфильтровать ресурсы: вывести те ресурсы, у которых больше 20 просмотров (HitsPage), комментов больше 0 (Tickets), и которые опубликованы больше месяца назад.
Написал сниппет, но при обработке большого количества ресурсов страница с вызовом сниппета не загружается. Как оптимизировать код?
Написал сниппет, но при обработке большого количества ресурсов страница с вызовом сниппета не загружается. Как оптимизировать код?
$mounth = 2629743;
$date = strtotime('now')-$mounth;
$where = array(
'parent' => 19,
'publishedon:<' => $date
);
$resources = $modx->getCollection('modResource', $where);
foreach ($resources as $k => $res) {
//получаем id
$id = $res->get('id');
//получаем количество комментов
$q = $modx->newQuery('modResource', $id);
$q->leftJoin('TicketThread','TicketThread', "`TicketThread`.`name` = 'resource-{$id}'");
$q->leftJoin('TicketComment','TicketComment', "`TicketThread`.`id` = `TicketComment`.`thread`");
$q->select('COUNT(`TicketComment`.`id`) as `comments`');
$count = 0;
if ($q->prepare() && $q->stmt->execute()) {
$count = (integer) $q->stmt->fetch(PDO::FETCH_COLUMN);
}
//получаем дату, количество просмотров и заголовок
$date = $res->get('publishedon');
$hits = $res->getTVValue(3);
$titles = $res->get('pagetitle');
//если опубликован больше месяца назад, просмотров больше 20 и комментов больше 0, то выводим
if ($hits >= 20 and $count > 0) {
$output .= $date. " | П: ". $hits. " | К: ". $count. "</br>". $titles. "<hr>";
}
}
return $output;
Поблагодарить автора
Отправить деньги
Комментарии: 6
Убрать getCollection, использовать getIterator
modxclub.ru/topics/xpdogetiterator-vmesto-xpdogetcollection.html
В критерию можно добавить выбор только нужных колонок (publishedon, pagetitle, id)
Можно сразу присоединить и таблицу с TV hits по contentid и tmplvarid = 3
modxclub.ru/topics/xpdogetiterator-vmesto-xpdogetcollection.html
В критерию можно добавить выбор только нужных колонок (publishedon, pagetitle, id)
Можно сразу присоединить и таблицу с TV hits по contentid и tmplvarid = 3
Я не уверен, конечно, но лучше использовать newQuery. С getIterator почти нет опыта, но читал, что меньше всего нагрузка именно при newQuery.
Вы путаете, newQuery — это создание запроса xPDOQuery, а getCollection и getIterator получение результата на основании параметров (это может быть и обычный массив и xPDOQuery)
В случае getCollection и getIterator вы получаете объекты xpdo, из которых вы можете получить подготовленные данные через метод get.
В случае getCollection и getIterator вы получаете объекты xpdo, из которых вы можете получить подготовленные данные через метод get.
if ($q->prepare() && $q->stmt->execute()) {
$count = (integer) $q->stmt->fetch(PDO::FETCH_COLUMN);
}
А в данном случае вы получаете результат из базы данных Вы путаете, newQuery — это создание запроса xPDOQuery, а getCollection и getIterator получение результата на основании параметров (это может быть и обычный массив и xPDOQuery)Как я понял — объекты не нужно получать, ведь там просто вывод результатов.
В случае getCollection и getIterator вы получаете объекты xpdo, из которых вы можете получить подготовленные данные через метод get.
Я вчитался в код и офигел… Сначала выбираются минимум 2000 страниц, после чего для каждой из них идет запрос к базе.
Да, тут вообще вопрос в другом — как избавится от такого количества запросов.
Автор, окстись!
Очень плохой код.
Как это сейчас работает: сначала через getCollection забираются 2000+ ресурсов, которые опубликованы. Далее мы получаем их id и для каждого делаем запрос к бд!
Это очень плохая идея.
Как минимум те же id можно получить через newQuery — так будет быстрее.
А во вторых желательно сделать 1 запрос к бд, а не 2001.
Почитай мануалы.
А вообще я бы примерно так сделал (вообще не гарантирую, что будет работать, пишу на глазок).
Очень плохой код.
Как это сейчас работает: сначала через getCollection забираются 2000+ ресурсов, которые опубликованы. Далее мы получаем их id и для каждого делаем запрос к бд!
Это очень плохая идея.
Как минимум те же id можно получить через newQuery — так будет быстрее.
А во вторых желательно сделать 1 запрос к бд, а не 2001.
Почитай мануалы.
А вообще я бы примерно так сделал (вообще не гарантирую, что будет работать, пишу на глазок).
$mounth = 2629743;
$date = strtotime('now')-$mounth;
$where = array(
'parent' => 19,
'publishedon:<' => $date,
'comments:>' => 20
//тут надо добавить что-то про hits, но для этого сделать join таблицы modTemplateVar
);
$q = $modx->newQuery('modResource', $id);
$q->leftJoin('TicketThread','TicketThread', "`TicketThread`.`name` = 'resource-{$id}'");
$q->leftJoin('TicketComment','TicketComment', "`TicketThread`.`id` = `TicketComment`.`thread`");
$q->select('COUNT(`TicketComment`.`id`) as `comments`');
$q->where($where);
if ($q->prepare() && $q->stmt->execute()) {
$data = $q->stmt->fetch(PDO::FETCH_COLUMN);
foreach ($data as $res) {
//тут код вывода
}
}
Вариант такого типа будет работать в сотни раз быстрее
Переделал. Не уверен, что все правильно сделал, но работает в разы быстрее.
Условия выборки немного изменились: вывести статьи, у которых просмотров меньше 20, количество комментов = 0, и, которые опубликованы больше трех недель назад.
Условия выборки немного изменились: вывести статьи, у которых просмотров меньше 20, количество комментов = 0, и, которые опубликованы больше трех недель назад.
$week = 604800;
$cond_date = strtotime('now')-$week*3;
$q_test = " SELECT
modx_site_content.id,
modx_site_content.properties,
modx_site_content.publishedon,
modx_tickets_threads.comments
FROM
`modx_site_content`,
`modx_tickets_threads`
WHERE
modx_site_content.id = modx_tickets_threads.resource
AND
modx_site_content.parent = '19'";
$result = $modx->query($q_test);
$rows = $result->fetch();
do {
$id = $rows['id'];
$comments = $rows['comments'];
$date = $rows['publishedon'];
$visits = preg_replace("/[^0-9]/", '', $rows['properties']);
if ($comments == 0 and $visits <= 20 and $date < $cond_date) {
echo "<pre>";
echo "id = ". $id. "<br />";
echo "comments = ". $comments. "<br />";
echo "pubdate = ". date("Y-m-d",$date). "<br />";
echo "visits = ". $visits;
echo "</pre>";
}
}
while ($rows = $result->fetch());
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.