-
16-10-2019 - |
题
这是我的代码:
$catIds = array(7,8,9);
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect("*");
->addAttributeToFilter('category_ids', array('nin' => $catIds));
我想将所有不在类别ID列表中的产品中获取,但我的代码没有给出预期的结果。请告诉我路,谢谢。
解决方案
您需要加入拥有类别/产品关系的表。
我用来在类别列表中找到所有产品的集合的变体应该为您提供技巧:
(未经测试,但应该让您处于正确的轨道)
$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)的方法更好地做到这一点。
这种方法的好处
这对原始答案的好处是,您不会获得误报,因此它更快且易于错误。例如,假设您有一个产品:
- 衬衫(类别:1 | 2)
你想要 “找到所有不在中的产品 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” 桌子。所以 LEFT JOIN
将返回多个结果。
这是不希望的,因为
- 您的结果集将比需要的大,这将消耗超过必要的内存。尤其是,如果您有数千件商品的库存非常大。
- 您将需要在PHP中进行额外的检查,以确定结果是否为误报(例如,
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),则可以使用product_id不在产品ID的子程序中的地方,实际上是您需要排除的类别(不在此处给出)。
另一种反加入方法 回答 也将起作用。但是在这种情况下,您无法轻易添加其他条件。