วิธีการกรองผลิตภัณฑ์ไม่อยู่ในหมวดหมู่?


10

นี่คือรหัสของฉัน:

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

ฉันต้องการรับผลิตภัณฑ์ทั้งหมดที่ไม่อยู่ในรายการรหัสหมวดหมู่ แต่รหัสของฉันไม่ได้ให้ผลลัพธ์ที่คาดหวัง กรุณาช่วยบอกทางหน่อย


ผลลัพธ์ที่คุณคาดหวังกับผลลัพธ์ที่คุณได้รับคืออะไร
ahnbizcad

คำตอบ:


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' ไม่รวมแถวนั้น แต่รหัสผลิตภัณฑ์จะยังคงปรากฏสำหรับหมวดหมู่อื่น ๆ
greatwitenorth

สวัสดีในขณะที่รหัสย่อมามันทำงานได้ 100% รหัสที่เขียนจะแยกผลิตภัณฑ์ตามรายการหมวดหมู่ที่กำหนดในตัวแปร $ catIds หากผลิตภัณฑ์ปรากฏในมากกว่าหนึ่งหมวดหมู่และหมวดนั้นไม่รวมอยู่ในรายการยกเว้นก็จะปรากฏขึ้น ความผิดนั้นคือคุณไม่ได้ยกเว้นหมวดหมู่ทั้งหมด รหัสไม่สามารถอย่างน่าอัศจรรย์ (ตามที่เขียน) ทราบว่าสินค้าประเภทอื่น ๆ ปรากฏใน>
ProxiBlue

ฟังดูเหมือนคุณต้องการวิธีที่จะแยกรหัสผลิตภัณฑ์ซึ่งคุณสามารถรับรหัสข้างต้นได้อย่างง่ายดาย tep แรกจะสลับไปที่ IN จากนั้นรับรหัสผลิตภัณฑ์ที่ได้จากแบบสอบถามนี้แล้วใช้ในคอลเลกชันใหม่สำหรับผลิตภัณฑ์ ยิ่งไปกว่านั้นคือทำให้เป็นแบบสอบถามย่อยของการรวบรวมผลิตภัณฑ์ที่ไม่รวมอยู่ในรหัสผลิตภัณฑ์
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

ไม่มีเรื่องใหญ่เลยวีโอไอพีจะยังคงส่งคืนผลลัพธ์แรกเท่านั้นจากนั้นคุณเพิ่ม ยกเว้น ! ครั้งที่สองที่เรียกใช้แบบสอบถามนี้คุณมีผลลัพธ์เหมือนกัน:

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

วีโอไอพีจะบอกคุณว่าคุณยังไม่ได้เพิ่มเสื้อ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 เป็นโมฆะ"


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 ไม่ได้อยู่ในคิวรีย่อยของรหัสผลิตภัณฑ์จริง ๆ แล้วในหมวดหมู่ที่คุณต้องยกเว้น (ไม่ได้ให้ที่นี่)

วิธีการต่อต้านการเข้าร่วมจากคำตอบอื่นจะได้ผลเช่นกัน แต่ในกรณีนี้คุณไม่สามารถเพิ่มเงื่อนไขเพิ่มเติมได้อย่างง่ายดาย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.