Answers:
您需要加入包含类别/产品关系的表。
我用于在类别列表中查找所有产品的系列的一个变体应该可以帮助您:
(未经测试,但应该可以让您处于正确的轨道)
$productCollection = Mage::getResourceModel('catalog/product_collection')
->setStoreId(0)
->joinField('category_id', 'catalog/category_product', 'category_id', 'product_id=entity_id', null, 'left')
->addAttributeToFilter('category_id', array('nin' => $catIds))
->addAttributeToSelect('*');
$productCollection->getSelect()->group('product_id')->distinct(true);
$productCollection->load();
参考:http : //www.proxiblue.com.au/blog/Collection_of_products_in_all_child_categories/
以下代码将为您工作:
$catIds = array(7,8,9);
$_productCollection = Mage::getModel('catalog/product')
->getCollection()
->joinField('category_id', 'catalog/category_product', 'category_id', 'product_id = entity_id', null, 'left')
->addAttributeToFilter('category_id', array('nin' => array('finset' => $catIds)))
->addAttributeToSelect('*');
我发现使用反连接(Magento 1.9)可以更好地做到这一点。
与原始答案相比,这样做的好处是您不会得到误报,因此更快,更不易出错。例如,假设您有一个产品:
您想“找到所有不在的产品category 3
,然后将它们添加到category 3
”。因此,您运行一个NOT IN
查询,它将返回两行(name | category_id)
:
1. "Shirt" | 1
2. "Shirt" | 2
没什么大不了的,Magento仍然只会返回第一个结果,然后将其添加。除了!第二次运行此查询,您将得到相同的结果:
1. "Shirt" | 1
2. "Shirt" | 2
Magento会告诉您您还没有添加这件衬衫category 3
。这是因为,当产品属于多个类别时,它们在“ catalog_product_entity”表中将具有多个行。因此,a LEFT JOIN
将返回多个结果。
这是不希望的,因为
in_array($categoryThree, $product->getCategories())
),这意味着您将遍历不必要的结果。这会使您的脚本/代码变慢,尤其是在库存较大的情况下。// All products not in this category ID
$notInThisCatId = '123';
$filteredProducts = Mage::getModel('catalog/product')->getCollection();
$filteredProducts
->joinField('category_id', 'catalog_category_product', 'category_id', 'product_id=entity_id', ['category_id'=>$notInThisCatId], 'left');
$filteredProducts
->addAttributeToFilter('category_id', [
['null' => true]
]);
生成的SQL查询如下所示:
SELECT
DISTINCT `e`.*, `at_category_id`.`category_id`
FROM `catalog_product_entity` AS `e`
LEFT JOIN `catalog_category_product` AS `at_category_id`
ON (at_category_id.`product_id`=e.entity_id) AND (at_category_id.category_id = '123')
WHERE (at_category_id.category_id IS NULL)
GROUP BY `e`.`entity_id`;
给定产品和产品<=>类别关系表:
catalog_product_entity
+-----------+
| ENTITY_ID |
+-----------+
| 423 |
| 424 |
| 425 |
+-----------+
catalog_category_product
+-------------+------------+
| CATEGORY_ID | PRODUCT_ID |
+-------------+------------+
| 3 | 423 |
| 123 | 424 |
| 3 | 425 |
+-------------+------------+
您的查询是在说:“给我所有行‘catalog_product_entity’,并粘贴在‘CATEGORY_ID’从列catalog_category_product‘’,然后就给我行认为CATEGORY_ID = 124”。
因为是左联接,所以它将始终具有“ catalog_product_entity”中的行。对于任何无法匹配的行,它将为NULL
:
结果
+-------------+-------------+
| ENTITY_ID | CATEGORY_ID |
+-------------+-------------+
| 423 | NULL |
| 424 | 123 |
| 425 | NULL |
+-------------+-------------+
从那里,查询然后说:“好吧,现在给我提供category_id为NULL的所有内容”。
不像看起来那样容易。
这是基于GROUP_CONCAT的选项,因为它的默认限制(1024,但可以增加)当然可以,以逗号分隔的产品类别ID。
$categoryIdsToExclude = array(1, 2, 4); // Category IDs products should not be in
$collection = Mage::getModel('catalog/product')->getCollection();
$selectCategories = $collection->getConnection()->select();
$selectCategories->from($collection->getTable('catalog/category_product'), array('product_id', 'category_id'));
$mysqlHelper = Mage::getResourceHelper('core');
$mysqlHelper->addGroupConcatColumn(
$selectCategories,
'category_ids_set',
'category_id',
','
);
$selectCategories->group('product_id');
$collection->getSelect()->joinLeft(
array('category_ids_set_table' => new Zend_Db_Expr('(' . $selectCategories->__toString() . ')')),
'category_ids_set_table.product_id = e.entity_id',
array('category_ids_set' => 'category_ids_set_table.category_ids_set')
);
foreach ($categoryIdsToExclude as $val) {
$collection->getSelect()->where('NOT FIND_IN_SET(?, category_ids_set)', $val);
}
另外(如果您不喜欢GROUP_CONCAT),则可以使用WHERE product_id NOT IN,而产品ID的子查询实际上是您需要排除的IN类(在此不提供)。
另一个答案中的反联接方法也将起作用。但是在这种情况下,您无法轻松添加其他条件。