Difference between getSize() and count() on collection
I have heard many times that they both are the same. But I am facing a weird issue, in the product collection of CatalogSearch module, count() is returning correct product count while getSize() is returning zero.
So, basically this is what I am getting:
$collection->count(); //correct count
$collection->getSize(); //0
But I want the getSize() to have correct count as it decides whether to show pagination and products in the search page or not. I am using Inner Join, Left Join and Where condition only in the collection to be more specific.
Any ideas why I am getting this weird issue?
Thanks
UPDATE:
My previous question, How to clone the collection in Magento? I wanted to perform two different operations on one collection. The first collection shows correct getSize(), but then if the getSize() is zero, I removed the WHERE clause and gave new WHERE condition. After this, I am getting correct raw SQL what I expected, and running it in MySQL also gives a correct set of records, but only getSize() on the collection is giving zero counts.
So basically I may need to reload the collection, as getSize() is taking old count. Makes sense?
Solutions
Be careful. This is correct, but the methods are overwritten in Varien_Data_Collection_Db
as described by Marius
Just have a look into
// \Varien_Data_Collection::getSize
public function getSize()
{
$this->load();
if (is_null($this->_totalRecords)) {
$this->_totalRecords = count($this->getItems());
}
return intval($this->_totalRecords);
}
// \Varien_Data_Collection::count
public function count()
{
$this->load();
return count($this->_items);
}
So it should on this low level be the same. Both methods load the collection and count the items.
UPDATE
Oh I see a problem: getSize() caches the _totalRecords, this means it is not recalculated. Check where _totalRecords
is set?
Most (if not all) the collections extend Varien_Data_Collection_Db
. Here are the 2 methods from this class
public function getSize()
{
if (is_null($this->_totalRecords)) {
$sql = $this->getSelectCountSql();
$this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams);
}
return intval($this->_totalRecords);
}
public function count() //inherited from Varien_Data_Collection
{
$this->load();
return count($this->_items);
}
There is a difference. For getSize()
the collection is not loaded. For count()
it is.
Usually collection models use the same getSize()
method as above and only override getSelectCountSql()
.
In getSelectCountSql()
the limit is reset in order to get the total number of records available for the set filters (where
statement).
See how the getSelectCountSql()
works
public function getSelectCountSql()
{
$this->_renderFilters();
$countSelect = clone $this->getSelect();
$countSelect->reset(Zend_Db_Select::ORDER);
$countSelect->reset(Zend_Db_Select::LIMIT_COUNT);
$countSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
$countSelect->reset(Zend_Db_Select::COLUMNS);
$countSelect->columns('COUNT(*)');
return $countSelect;
}
This answer shows up in google for "magento getSize wrong" and similar searches so I would like to add a possible scenario that might be useful to someone
When you have a group statement in your query and you do a
SELECT COUNT(DISTINCT e.entity_id) ... GROUP BY ( at_id_art.value )
Mysql will return a count for EACH of the groups, so Varien_Data_Collection_Db::getSize() will return the wrong answer, this is because this function fetches the first row:
public function getSize()
{
if (is_null($this->_totalRecords)) {
$sql = $this->getSelectCountSql();
$this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams);
}
return intval($this->_totalRecords);
}
When it populates
$this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams);
It selects the first row and therefore returns the total of the first group as the total size.
I ended up coming up with this code to count, based on the unique values of the attributes in my query.
$select = clone $collection->getSelect();
$group = $select->getPart(Zend_Db_Select::GROUP);
$select->reset(Zend_Db_Select::GROUP)->reset(Zend_Db_Select::COLUMNS)->columns("COUNT(DISTINCT {$group[0]})");
$totalCount = $collection->getConnection()->fetchOne($select);