Kategorilerde DEĞİL ürünler nasıl filtrelenir?


10

İşte benim kod:

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

Kategori kimlikleri listesinde olmayan tüm ürünleri almak istiyorum, ancak kodum beklenen sonucu vermedi. Lütfen bana yolu göster, teşekkürler.


Elde ettiğiniz sonuçlara kıyasla beklediğiniz sonuç neydi?
ahnbizcad

Yanıtlar:


16

Kategori / ürün ilişkilerini içeren tabloya katılmanız gerekir.

Bir kategori listesinde tüm ürünleri bulmak için kullandığım koleksiyonun bir varyasyonu sizin için hile yapmalıdır:

(denenmemiş, ancak sizi doğru yola sokmalı)

$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
Bir ürün birden fazla kategoride görünüyorsa, bu işe yaramaz. 'Nin' sadece bir satırı hariç tutar, ancak diğer kategoriler için ürün kimliği yine de gelir.
greatwitenorth

Merhaba, Kod duruyor gibi,% 100 çalışıyor. Yazılan kod, $ catIds değişkenindeki verilen kategori listesine göre ürünü hariç tutacaktır. Ürün birden fazla kategoride görünüyorsa ve bu kategori hariç tutma listesine dahil edilmemişse, görünür. Hata, tüm kategorileri hariç tutmamanızdır. Kod sihirli bir şekilde (yazıldığı gibi) ürünün hangi kategorilerde göründüğünü
bilemez

Daha çok, yukarıdaki koddan kolayca türetebileceğiniz ürün kimlikleri tarafından hariç tutulmanın bir yolunu istediğiniz gibi geliyor. İlk tepesi IN'ye takas etmek, daha sonra bu sorgudan sonuçlanan ürün Kimlikleri almak ve daha sonra verilen ürünler id ile hariç ürünler için yeni bir koleksiyonda kullanmak olacaktır. Daha da iyisi, onu ürün kimlikleri hariç tutulan ürün koleksiyonunun alt sorgusu yapmaktır.
ProxiBlue

5

Aşağıdaki kod sizin için çalışacaktır:

$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

Anti-join (Magento 1.9) kullanarak bunu yapmanın biraz daha iyi bir yolunu buldum.

Bu yaklaşımın faydaları

Bunun orijinal yanıta göre yararı, yanlış pozitifler elde etmemeniz ve sonuç olarak daha hızlı ve daha az hataya yatkın olmasıdır. Örneğin, tek bir ürününüz olduğunu varsayalım:

  1. Gömlek (kategorilerde: 1 | 2)

Sen istiyoruz "değil tüm ürünleri bulmak category 3, sonra bunları eklemek category 3" . Böylece bir NOT INsorgu çalıştırırsınız ve iki satır döndürür (name | category_id):

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

Önemli değil, Magento yine de sadece ilk sonucu döndürecek ve sonra ekleyeceksiniz. Dışında ! Bu sorgu ikinci kez çalıştırıldığında aynı sonuçlara sahip olursunuz:

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

Ve Magento hala bu gömleği henüz eklemediğini söyleyecek category 3. Bunun nedeni, bir ürün birden çok kategoriye ait olduğunda, "catalog_product_entity" tablosunda birden çok satıra sahip olmalarıdır . Ve böylece a LEFT JOINbirden çok sonuç döndürür.

Bu istenmeyen bir durum çünkü

  1. Sonuç kümeniz gerekenden daha büyük olacak ve bu da gerektiğinden daha fazla bellek kullanacak. Özellikle binlerce öğeden oluşan çok büyük bir envanteriniz varsa.
  2. Sonuçların yanlış pozitif olup olmadığını belirlemek için PHP'de ek bir kontrol in_array($categoryThree, $product->getCategories())yapmanız gerekecektir (örn. ), Yani gereksiz sonuçlara göz atacaksınız. Bu, özellikle büyük envanterlerde komut dosyanızı / kodunuzu yavaşlatır.

Çözüm

// 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]
    ]);

Oluşturulan SQL sorgusu şöyle görünecektir:

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

Açıklama:

Ürün ve ürün <=> kategori ilişki tabloları göz önüne alındığında:

catalog_product_entity +-----------+ | ENTITY_ID | +-----------+ | 423 | | 424 | | 425 | +-----------+

catalog_category_product +-------------+------------+ | CATEGORY_ID | PRODUCT_ID | +-------------+------------+ | 3 | 423 | | 123 | 424 | | 3 | 425 | +-------------+------------+

Sorgu, diyor "bana tüm satırları vermek catalog_product_entity '' ve yapıştırmak 'category_id' dan kolona catalog_category_product '' . Ardından yalnızca bu category_id = 124 me satırları vermek" .

Bu bir sol birleşim olduğu için, her zaman "catalog_product_entity" satırları olacaktır . Eşleştirilemeyen satırlar için NULL:

Sonuç +-------------+-------------+ | ENTITY_ID | CATEGORY_ID | +-------------+-------------+ | 423 | NULL | | 424 | 123 | | 425 | NULL | +-------------+-------------+

Oradan, sorgu "tamam, şimdi bana category_id NULL olduğu her şeyi ver" diyor .


1

Göründüğü kadar kolay değil.

Varsayılan sınır (1024, ancak elbette artırılabilir) olduğundan, GROUP_CONCAT tabanlı seçenek, virgül kümesiyle ayrılmış ürün kategorisi kimlikleriyle uyumlu olmalıdır.

$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);
}

Ayrıca (GROUP_CONCAT ürününü beğenmediyseniz) WHERE product_id öğesini bir ürün kimliğinin alt sorgusunda aslında hariç tutmanız gereken kategorilerde (burada vermeyin) kullanabilirsiniz.

Başka bir cevaptan anti-join yaklaşımı da işe yarayacaktır. Ancak bu durumda kolayca ek koşullar ekleyemezsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.