カテゴリーに含まれない製品をフィルタリングする方法は?


10

これが私のコードです:

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

カテゴリIDのリストに含まれていないすべての製品を取得したいのですが、コードで期待した結果が得られませんでした。道を教えてください、ありがとう。


期待した結果と得た結果はどうでしたか?
ahnbizcad 2017

回答:


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();

ref:http : //www.proxiblue.com.au/blog/Collection_of_products_in_all_child_categories/


1
これは、製品が複数のカテゴリに表示される場合は機能しないようです。「nin」はその1つの行を単に除外しますが、製品IDは他のカテゴリでも引き続き表示されます。
greatwitenorth 2016

こんにちは、コードはそのままで、100%機能します。記述されたコードは、変数$ catIdsの特定のカテゴリリストに従って製品を除外します。商品が複数のカテゴリに表示され、そのカテゴリが除外リストに含まれていない場合は、表示されます。その場合の欠点は、すべてのカテゴリを除外していないことです。このコードは、(記述されているとおり)製品が表示される他のカテゴリを魔法のように知ることはできません>
ProxiBlue

上記のコードから簡単に導出できる製品IDで除外する手段が必要であるように聞こえます。最初の手順は、INにスワップしてから、このクエリから生成された製品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. シャツ(カテゴリー:1 | 2)

あなたはしたくない「で、すべての製品を見つけcategory 3、その後、それらを追加しますcategory 3NOT INクエリを実行すると、2つの行が返されます(name | category_id)

1. "Shirt" | 1
2. "Shirt" | 2

たいしたことではありません。Magentoは最初の結果のみを返し、それを追加します。を除いて!このクエリを2回目に実行すると、同じ結果になります。

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`;

説明:

productとproduct <=> categoryの関係テーブルを考えます:

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カテゴリです(ここでは指定しません)。

別の回答からの反結合アプローチも機能します。ただし、この場合、条件を簡単に追加することはできません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.