उत्पादों को श्रेणी में फ़िल्टर करने के लिए कैसे नहीं?


10

यहाँ मेरा कोड है:

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

मैं सभी उत्पादों को श्रेणी आईडी की सूची में नहीं लाना चाहता, लेकिन मेरे कोड ने अपेक्षित परिणाम नहीं दिया। कृपया मुझे रास्ता दिखाओ, धन्यवाद।


आप जो परिणाम प्राप्त कर रहे थे, उसके परिणाम क्या थे?
एहनबिजद

जवाबों:


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
यदि कोई उत्पाद एक से अधिक श्रेणी में आता है तो यह काम नहीं करता है। 'निन' केवल उस एक पंक्ति को बाहर करता है, लेकिन उत्पाद आईडी अभी भी अन्य श्रेणियों के लिए आएगी।
महानवित्नर्थ

नमस्ते, जैसे ही कोड खड़ा होता है, यह 100% काम करता है। लिखित कोड, उत्पाद को दिए गए श्रेणी सूची के अनुसार चर $ catIds में शामिल नहीं करेगा। यदि उत्पाद एक से अधिक श्रेणी में प्रकट होता है, और वह श्रेणी बहिष्करण सूची में शामिल नहीं है, तो ठीक है, यह दिखाई देगा। इसके बाद दोष यह है कि आप सभी श्रेणियों को नहीं छोड़ रहे हैं। कोड जादुई रूप से नहीं लिखा जा सकता है (जैसा कि यह लिखा गया है) पता है कि उत्पाद किस अन्य श्रेणियों में दिखाई देता है
ProxiBlue

अधिक ध्वनि की तरह आप उत्पाद आईडी द्वारा बाहर निकालने का एक साधन चाहते हैं, जिसे आप आसानी से उपरोक्त कोड बना सकते हैं। पहला टेप IN को स्वैप करना होगा, फिर उत्पाद Ids प्राप्त करें, जिसके परिणामस्वरूप यह क्वेरी बनेगी, और फिर उत्पादों के लिए एक नए संग्रह में उपयोग करके, दिए गए उत्पादों को आईडी द्वारा छोड़कर। इससे भी बेहतर यह है कि इसे उत्पाद उत्पाद संग्रह के एक उपश्रेणी के रूप में बनाया जाए जो कि उत्पाद आईडी द्वारा बाहर रखा गया हो।
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 3category 3 चाहते हैं , फिर उन्हें जोड़ें " । इसलिए आप एक NOT INक्वेरी चलाते हैं , और यह दो पंक्तियों को लौटा देगा (name | category_id):

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

कोई बड़ी बात नहीं, Magento अभी भी केवल पहला परिणाम लौटाएगा, और फिर आप इसे जोड़ देंगे। को छोड़कर ! दूसरी बार यह क्वेरी चलने पर, आपके पास समान परिणाम होंगे:

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

और Magento आपको बताएगा कि आपने अभी भी इस शर्ट को नहीं जोड़ा है category 3। ऐसा इसलिए है क्योंकि जब कोई उत्पाद कई श्रेणियों का होता है, तो उनके पास "कैटलॉग_प्रोडक्ट_एंटिटी" तालिका में कई पंक्तियाँ होंगी । और इसलिए एक LEFT JOINसे अधिक परिणाम आएंगे।

यह अवांछनीय है क्योंकि

  1. आपका परिणाम सेट आवश्यकता से अधिक बड़ा होगा, जो आवश्यकता से अधिक मेमोरी का उपयोग करेगा। विशेष रूप से इसलिए यदि आपके पास हजारों मदों की एक बहुत बड़ी सूची है।
  2. परिणामों को गलत सकारात्मक (उदाहरण के लिए in_array($categoryThree, $product->getCategories())) हैं, तो यह निर्धारित करने के लिए आपको PHP में एक अतिरिक्त जांच करने की आवश्यकता होगी , जिसका अर्थ है कि आप अनावश्यक परिणामों के माध्यम से लूप करेंगे। यह आपकी स्क्रिप्ट / कोड को धीमा कर देगा, विशेष रूप से बड़े आविष्कारों के साथ।

समाधान

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

आपकी क्वेरी कह रही है, "मुझे " कैटलॉग_प्रोडक्ट_एंटिटी " में सभी पंक्तियां दें , और " कैटगरी_आईडी " कॉलम पर " कैटलॉग_कैटरोरी_प्रोडक्ट " से पेस्ट करें । इसके बाद बस मुझे उस श्रेणी_आईडी = 124" की पंक्तियां दें

क्योंकि यह लेफ्ट जॉइन है, इसलिए इसमें हमेशा "कैटलॉग_प्रोडक्ट_एंटिटी" से पंक्तियाँ होंगी । किसी भी पंक्तियों के लिए जिसका मिलान नहीं किया जा सकता है, यह होगा NULL:

परिणाम +-------------+-------------+ | ENTITY_ID | CATEGORY_ID | +-------------+-------------+ | 423 | NULL | | 424 | 123 | | 425 | NULL | +-------------+-------------+

वहां से, क्वेरी तब कहती है, "ठीक है, अब मुझे वह सब कुछ दे दो जहाँ category_id NULL है"


1

इतना आसान नहीं जितना दिख सकता है।

यहाँ GROUP_CONCAT-आधारित विकल्प है क्योंकि यह डिफ़ॉल्ट सीमा है (1024 लेकिन निश्चित रूप से बढ़ाया जा सकता है) उत्पाद श्रेणी की आईडी के साथ अल्पविराम सेट द्वारा ठीक होना चाहिए।

$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 का उपयोग नहीं कर सकते हैं, उत्पाद ID की एक उपश्रेणी में नहीं हैं वास्तव में उन श्रेणियों में हैं जिन्हें आपको बाहर करने की आवश्यकता है (इसे यहां नहीं देना)।

दूसरे उत्तर से विरोधी जुड़ने का तरीका भी काम करेगा। लेकिन इस मामले में आप आसानी से अतिरिक्त शर्तें नहीं जोड़ सकते।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.