$categories = PostCategoryQuery::create()->find();
$categories_array = [];
foreach ($categories as $k => $category):
$posts_count = PostQuery::create()->filterByPostCategory($category)->count();
$categories_array[$k]['category'] = $category->getName();
$categories_array[$k]['count'] = $posts_count;
endforeach;
uasort($categories_array, "sortByCount");
function sortByCount($a, $b) {
return $a['count'] > $b['count'] ? -1 : 1;
}
I want to get 'categories' array order by numbers of its related posts, I think there must be a way to make my code shorter, hoping get some suggestions, thanks~
If in your ORM you could use a simple query with group by you simply could perform a select like
select category, count(*)
from post_category
inner join post on post_category.category_id = post.category_id
group by category
order by count(*)
and then your code will be reduced to the query..
I don't know your model exactly, but I would recommend something like that:
$categories_array = PostQuery::create('pq')
->joinPostCategory('pc')
->withColumn('COUNT(pq.id)', 'count')
->groupBy('pc.id')
->select(array('pc.name', 'count'))
->orderBy('count')
->find();
// Should return PropelArrayCollection(
// array('pc.name' => 'category1', 'count' => 123),
// array('pc.name' => 'category2', 'count' => 234)
// )
This way you avoid object hydrating as you do only select the columns that you need.
Related
Below is my fetch code for sphinx. We have a filter named typeId which we use to compare bureau type. Now I have added one more filter named as altTypeId. Now I have to compare typeId and altTypeId both for same value such typeId = 6 OR altTypeId = 6.
I have tried several solutions but no one is working. I followed the solution on this link: https://sphx.org/forum/view.html?id=13474 but its not working as well.
protected function fetch() {
$this->_searchCriteria->orders = $this->sort;
$this->pagination->validateCurrentPage = false;
$this->_searchCriteria->paginator = $this->pagination;
$this->_searchCriteria->query.=" profileTypePlaceholderTexxxxxt";
Yii::app()->search->SetLimits($this->pagination->offset, $this->pagination->limit);
Yii::app()->search->SetFieldWeights($this->_fieldWeights);
if ($this->_searchCriteria->query)
Yii::app()->search->setMatchMode(SPH_MATCH_ALL);
else
Yii::app()->search->setMatchMode(SPH_MATCH_FULLSCAN);
Yii::app()->search->setFieldWeights(array(
'primary_comp' => 100,
'premium' => 80,
'standard' => 60,
'free' => 40,
'comp' => 20,
'title' => 5,
'description' => 5,
));
//Yii::app()->search->SetSortMode(SPH_SORT_EXTENDED, '#weight DESC');
Yii::app()->search->SetSortMode(SPH_SORT_EXTENDED,'#weight DESC, random DESC');
foreach ($this->_searchCriteria->filters as $filter) {
if ($filter[0] == 'range')
Yii::app()->search->SetFilterFloatRange($filter[1], (float) $filter[2] + 0.01, (float) $filter[3]);
else
Yii::app()->search->SetFilter($filter[0], array($filter[1]));
}
$results = Yii::app()->search->Query($this->_searchCriteria->query, $this->_searchCriteria->from);
$this->_data = array();
$this->_keys = array();
$this->_itemCount = $results['total'];
$this->pagination->itemCount = $this->_itemCount;
if ($this->_itemCount) {
$this->_populateItems($results['matches']);
}
}
Frankly putting both values in the same sphinx attrbute, seems easiest. MVA is perfect for this!
Couple of ways could be done, but just...
sql_query = SELECT id,title, CONCAT_WS(',',typeId,altTypeId) AS typeids FROM ...
sql_attr_multi = uint typeids from field
then just
->SetFilter('typeids', array(6));
finds results from EITHER column.
Otherwise if really want to only do it at query time, its something like
if ($filter[0] == 'typeid') {
Yii::app()->search->SetSelect("*, (typeid = {$filter[1]} OR altTypeId = {$filter[1]}) AS myfilter");
Yii::app()->search->SetFilter('myfilter', array(1));
} else ...
I am making an application using CakePHP. I made an action which uses saveAll function.
And I thought it works well, because it doesn't need so much data, but it took over 3 minutes to save using saveAll, or other save function.
Does anyone find my mistakes?
phpMyadmin's columns:
id, rank, school_detail_id, total_score, school_name,
(there is about 300~400 data)
public function rank_update(){
$check_scores = $this->ClubScore->find('all', array('fields'=>array('id','total_score')));
$check_scores2 = Set::sort($check_scores, "{n}.ClubScore.total_score","DESC");
$rank_id=0;
$temp_score=0;
$temp = null;
$for_count=0;
foreach ($check_scores2 as $check_score):
if($temp_score != $check_score['ClubScore']['total_score']){
$rank_id++;
$temp_score = $check_score['ClubScore']['total_score'];
// make ranking by score. same score is same ranking.
}
$this->ClubScore->id = $check_score['ClubScore']['id'];
$this->ClubScore->saveField('rank', $rank_id);
endforeach;
}
Divide the query from foreach to simpler approach
get distinct total_score in desc order
$data = $this->ClubScore->find('all', array('fields'=>array('DISTINCT total_score'), 'order' => 'total_score DESC'));
and then simply save the key as rank for each total_score using updateAll and foreach
Thank you very much Abhishek and AgRizzo ,Nunser!!
Now, I've completely solved this problem. It takes only 1 or 2 seconds!!!!!
Here is the source code.
public function rank_update(){
$data = $this->ClubScore->find('all', array('fields'=>array('DISTINCT total_score'), 'order' => 'total_score DESC'));
$check_scores = $this->ClubScore->find('all', array('fields'=>array('id','total_score')));
$check_scores2 = Set::sort($check_scores, "{n}.ClubScore.total_score","DESC");
$ii = 0;
$temp = 0;
foreach($check_scores2 as $scores):
if($data[$ii]['ClubScore']['total_score']
== $scores['ClubScore']['total_score']){
$temp=$ii+1;
}else{
$ii++;
$temp=$ii+1;
}
$update_arr[] = array(
'ClubScore' => array(
'id' => $scores['ClubScore']['id'],
'rank' =>$temp,
)
);
endforeach;
$update_arr = Set::sort($update_arr, "{n}.ClubScore.id","ASC");
var_dump($update_arr);
foreach($update_arr as $update_arrs):
$this->ClubScore->updateAll(
array(
'ClubScore.rank' => $update_arrs['ClubScore']['rank'],
),
array(
'ClubScore.id' => $update_arrs['ClubScore']['id'],
)
);
endforeach;
}
Thank you very much.
Best regards.
I am creating a search form where user can enter state,city or zip in a single input field. I am using following code:
$collection = Mage::getModel('searchservice/service')->getCollection();
$collection->addFieldToFilter('compstate',array('like'=>$post['input1']));
foreach ($collection as $record)
{
$data[] = $record;
}
Mage::register('data', $data);
$this->renderLayout();
It is returning compstate result but I want that user can enter any field like zip and city also. How to use or condition here?
Like this:
echo Mage::getModel("modelalias/entityname")
->getCollection()
->addFieldToFilter(
array(
'first_condition',
'second_condition'
),
array(
array('eq' => 1),
array('eq' => 0),
)
)
->getSelect();
The above query will produce a SQL string like this:
SELECT `main_table`.* FROM `mytablename` AS `main_table`
WHERE (((first_condition = 1) or (second_condition = 0)))
You should be able to modify this to suit your need.
I have an array of posts that I want to sort - but before I do, I want to find the id of the post with the highest number of likes.
I loop through the array using a foreach. Although it seems like a waste to do two foreach loops for this - I don't know if there's an alternative when trying to find the highest value beforehand?
Array
(
[0] => Array
(
[id] => 162
[like_count] => 2
etc.
)
[1] => Array
(
[id] => 165
[like_count] => 23
etc.
)
)
So the second post has the highest amount of likes, so I need the ID of 165 - then when I loop through I can do something like
foreach ($posts as $post){
if($most_liked_id == $post["id"]){
// this post is the most liked!
}
}
Any help would be much appreciated - thanks!
$highest = 0;
$highest_id = 0;
foreach($array as $a) {
if($a['like_count'] > $highest) {
$highest = $a['like_count'];
$highest_id = $a['id'];
}
}
Hope I understood you correctly :)
This looks like data retrieved from a database. If so, use the ORDER BY like_count DESC clause in the SQL.
The ID of the post with the most likes will then be at $posts[0]['id'] before you sort by your other method.
very easy task, you loop through your posts.
function get_max_like_post($posts) {
$max_like = 0;
$max_like_post = array();
foreach ($posts as $post) {
if ($post['like_count'] > $max_like) {
$max_like = $post['like_count'];
$max_like_post = $post;
}
}
return $max_like_post['id']
}
You could use usort.
$posts = array(
array('id' => 161, 'like_count' => 0),
array('id' => 162, 'like_count' => 6),
array('id' => 4, 'like_count' => 2),
);
function like_sort($a, $b) {
if ($a['like_count'] == $b['like_count']) {
return 0;
}
return ($a['like_count'] > $b['like_count']) ? -1 : 1;
}
usort($posts, 'like_sort');
// The first element in the array is now the one with the highest like_count.
echo $posts[0]['id']; // 162
Try this:
usort($posts, function($item) { return -$item['like_count']; });
$id = empty($posts) ? null : $posts[0]['id'];
Where $posts is the input array.
Explanation:
first you sort the posts by like count in decreasing fashion
then you get the top post id if there any posts, null otherwise.
What's good about this solution is that you can also select first n posts.
$highest_post_likes = 0;
$highest_post_id = 0;
for($i = 0; $i < sizeof($posts); $i++) {
if ( $posts[$i][like_count] > $highest_post_likes ) {
$highest_post_likes = $posts[$i][like_count];
$highest_post_id = $i;
}
}
// now you can use $posts[$highest_post_id]
Is those datas came from a database like MySQL? If is it, the simpliest solution is to put an "ORDER BY".
You can also make seperate the 'like_count' array keeping the same key than your first array and doing a asort (http://www.php.net/manual/fr/function.asort.php). You will have the key of the highest like count.
You can sort the array in descending order based on like_count and then pick up the id for the first array element.
You can use max function to get the highest value of likes:
foreach ($posts as $post){
$max[]=$post['like_count'];
}
echo max($max['id']);
I'm trying to pull out the sales totals for quarter 1. I can't seem to get this to work. Any suggestions?
$total = 0;
$orders = Mage::getModel('sales_order/collection')
->addAttributeToSelect('*')
->addAttributeToFilter('created_at', array(
'from' => '2012-01-01',
'to' => '2012-03-31'));
foreach ($orders as $order) {
$total += $order->getGrandTotal();
}
echo $total;
You're not getting the collection properly. There are multiple ways to do this, looks like you might've combined a couple methods:
Mage::getModel('sales/order')->getCollection() or
Mage::getResourceModel('sales/order_collection')
However, if all you really want is to sum the single attribute grand_total it is way more efficient to build your own query rather that loading the entire sales order collection:
$db = Mage::getSingleton('core/resource')->getConnection('core_read');
$salesTable = Mage::getSingleton('core/resource')->getTableName('sales/order');
list($total) = $db->fetchCol(
$db->select()
->from($salesTable, array('grand_total' => 'SUM(grand_total)'))
->where('DATE(created_at) >= ?', '2012-01-01')
->where('DATE(created_at) <= ?', '2012-03-31')
);
echo $total;