如何过滤不在类别中的产品?


10

这是我的代码:

$catIds = array(7,8,9);
$collection = Mage::getModel('catalog/product')->getCollection()
    ->addAttributeToSelect("*");
    ->addAttributeToFilter('category_ids', array('nin' => $catIds));

我想获取所有不在类别ID列表中的产品,但是我的代码未提供预期的结果。请给我指路,谢谢。


您期望得到的结果与获得的结果是什么?
ahnbizcad

Answers:


16

您需要加入包含类别/产品关系的表。

我用于在类别列表中查找所有产品的系列的一个变体应该可以帮助您:

(未经测试,但应该可以让您处于正确的轨道)

$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/


1
如果产品出现在多个类别中,则此方法似乎无效。“ nin”只是排除了这一行,但其他类别的产品ID仍然会出现。
greatwitenorth

嗨,正如代码所示,它可以100%工作。所写的代码将根据变量$ catIds中的给定类别列表排除产品。如果产品出现在多个类别中,并且该类别未包含在排除列表中,那么它将出现。缺点是您没有排他所有类别。该代码无法神奇地(按编写的方式)知道该产品还显示在其他哪些类别中
ProxiBlue

听起来更像是您想要一种通过产品ID排除的方法,您可以轻松地从上述代码中得出。第一个步骤是交换到IN,然后从该查询中获取生成的产品ID,然后在新的产品集合中使用该ID(不包括ID指定的产品)。更好的是使它成为产品集合的子查询,该子查询不包含产品ID。
ProxiBlue

5

以下代码将为您工作:

$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('*');

1

我发现使用反连接(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”表中将具有多个行。因此,a 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的所有内容”


1

不像看起来那样容易。

这是基于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类(在此不提供)。

另一个答案中的反联接方法也将起作用。但是在这种情况下,您无法轻松添加其他条件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.