这是我的代码:

$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. 衬衫(类别: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 将返回多个结果。

这是不希望的,因为

  1. 您的结果集将比需要的大,这将消耗超过必要的内存。尤其是,如果您有数千件商品的库存非常大。
  2. 您将需要在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的子程序中的地方,实际上是您需要排除的类别(不在此处给出)。

另一种反加入方法 回答 也将起作用。但是在这种情况下,您无法轻易添加其他条件。

许可以下: CC-BY-SA归因
scroll top