Reputation: 483
this might be a silly question, but well. I have the following code that retrieves all the products on my shop.
$products = Mage::getModel('catalog/product')->getCollection();
$products->addAttributeToFilter('status', 1);
$products->addAttributeToFilter('visibility', 4);
$products->addAttributeToFilter('type_id', 'simple');
$products->addAttributeToSelect('*');
$products->addStoreFilter($storeId);
$prodIds = $products->getAllIds();
Im aware of the:
$category = Mage::getModel('catalog/category')->load(9);
$products->addCategoryFilter($category);
to filter by a category ID, but how to get all products except one specific category ID ? (Magento 1.6.2)
Upvotes: 2
Views: 4279
Reputation: 2299
Here is the logic I came up with to resolve this problem.
Note: Should work in Magento 1.X
catalog/category
entity ID.It validates that we do not attempt to exclude the collection from the same category id twice.
public function addCategoryExclusionFilter(Mage_Catalog_Model_Resource_Product_Collection $collection, $category_id)
{
/* @var $resource Mage_Core_Model_Resource */
/* @var $category Mage_Catalog_Model_Category */
$resource = Mage::getModel('core/resource');
$category = Mage::getModel('catalog/category')->load($category_id);
$select = $collection->getSelect();
$tblccp = $resource->getTableName('catalog_category_product');
$tblAlias = $tblccp.'_'.$category_id;
if (! $category->getId()) {
Mage::throwException("Invalid `{$resource->getTableName('catalog/category')}`.`entity_id` value ({$category_id}).");
}
if (strpos($select->__toString(), $tblAlias) !== false) {
Mage::throwException("Category (ID: {$category->getId()}) already excluded from collection");
}
$select->joinLeft(array($tblAlias => $tblccp), "(`{$tblAlias}`.`product_id` = `e`.`entity_id` AND `{$tblAlias}`.`category_id` = '{$category->getId()}')", array());
$select->where("`{$tblAlias}`.`category_id` IS NULL");
}
Example of the MySQL query afterwards:
SELECT
`e`.*
FROM
`catalog_product_entity` AS `e`
LEFT JOIN
`catalog_category_product` AS `catalog_category_product_28` ON (
`catalog_category_product_28`.`product_id` = `e`.`entity_id` AND
`catalog_category_product_28`.`category_id` = '28'
)
WHERE
(`catalog_category_product_28`.`category_id` IS NULL)
What we are doing here is performing a join on the table which holds the relationship between product entities and category entities, BUT only where the record's category_id
is equal to the category id which we are looking to exclude. This is important because the catalog_product_entity
table has a 1:M relationship to the catalog_category_product
table (at the time of posting this answer, I do not see the other answers here addressing this). Then, we add a WHERE declaration that we only want to select records where the category_id
column for the joined table IS NULL (because there exists no record in the joined table, for product entities which we wish to select).
Upvotes: 0
Reputation: 2023
This is what I used:
$_productCollection = Mage::getModel('catalog/product')
->getCollection()
->addAttributeToSelect('*')
->addUrlRewrite();
Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($_productCollection);
Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($_productCollection);
$_productCollection->load();
$_productCollection->getSelect()->join(array('cats' => 'catalog_category_product'), 'cats.product_id = e.entity_id');
$_productCollection->getSelect()->where('cats.category_id not in (41)');
Upvotes: 1
Reputation: 426
I think this should work, presuming you know what category ID you want to filter out, but I can't test it right now
$catId = 9;
/* I'm almost positive 'e' is the alias used for catalog_product_entity, check your
query with echo (string) $products->getSelect(); if it doesn't work */
$products->getSelect()->join(array('cats' => 'catalog_category_product'), 'cats.product_id = e.entity_id');
$products->getSelect()->where('cats.category_id', array('neq' => $catId));
Upvotes: 3