Làm thế nào để lọc sản phẩm KHÔNG CÓ trong danh mục?


10

Đây là mã của tôi:

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

Tôi muốn nhận tất cả các sản phẩm không có trong danh sách id danh mục nhưng mã của tôi không cho kết quả như mong đợi. Xin chỉ cho tôi đường đi, cảm ơn.


kết quả bạn mong đợi so với kết quả bạn nhận được là gì?
ahnbizcad

Câu trả lời:


16

Bạn cần tham gia bảng giữ quan hệ danh mục / sản phẩm.

Một biến thể của bộ sưu tập tôi sử dụng để tìm tất cả các sản phẩm IN một danh sách các danh mục nên thực hiện thủ thuật cho bạn:

(chưa được kiểm tra, nhưng sẽ giúp bạn đi đúng hướng)

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


1
Điều này dường như không hoạt động nếu một sản phẩm xuất hiện trong nhiều danh mục. 'Nin' chỉ loại trừ một hàng đó, nhưng ID sản phẩm vẫn sẽ xuất hiện cho các danh mục khác.
greatwitenorth

Xin chào, vì mã đứng, nó hoạt động 100%. Mã được viết sẽ loại trừ sản phẩm theo danh sách danh mục đã cho trong biến $ catIds. Nếu sản phẩm xuất hiện trong nhiều danh mục và danh mục đó không được bao gồm trong danh sách loại trừ, thì nó sẽ xuất hiện. Lỗi sau đó là bạn không loại trừ tất cả các danh mục. Mã không thể kỳ diệu (vì nó được viết) biết những danh mục khác mà sản phẩm xuất hiện trong>
ProxiBlue

Âm thanh giống như bạn đang muốn một phương tiện để loại trừ bởi id sản phẩm, mà bạn có thể dễ dàng lấy được mã ở trên. Đầu tiên sẽ là hoán đổi thành IN, sau đó lấy Id sản phẩm tạo thành truy vấn này, sau đó sử dụng nó trong bộ sưu tập mới cho các sản phẩm, ngoại trừ các sản phẩm đã cho theo id. Thậm chí tốt hơn là làm cho nó trở thành một truy vấn con của bộ sưu tập sản phẩm được loại trừ bởi id sản phẩm.
ProxiBlue

5

Mã sau sẽ làm việc cho bạn:

$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

Tôi đã tìm thấy một cách tốt hơn để làm điều này, bằng cách sử dụng chống tham gia (Magento 1.9).

Lợi ích của phương pháp này

Lợi ích của điều này so với câu trả lời ban đầu là bạn sẽ không nhận được kết quả dương tính giả và kết quả là nhanh hơn và ít bị lỗi hơn. Ví dụ: giả sử bạn có một sản phẩm:

  1. Áo sơ mi (trong danh mục: 1 | 2)

Bạn muốn "tìm tất cả các sản phẩm không có trong category 3đó, sau đó thêm chúng vào category 3" . Vì vậy, bạn chạy một NOT INtruy vấn và nó sẽ trả về hai hàng (name | category_id):

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

Không có vấn đề gì lớn, Magento vẫn sẽ chỉ trả lại kết quả đầu tiên, và sau đó bạn thêm nó. Ngoại trừ ! Lần thứ hai truy vấn này được chạy, bạn có kết quả tương tự:

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

Và Magento sẽ cho bạn biết rằng bạn vẫn chưa thêm chiếc áo này vào category 3. Điều này là do khi một sản phẩm thuộc nhiều danh mục, chúng sẽ có nhiều hàng trong bảng "catalog_product_entity" . Và như vậy LEFT JOINsẽ trả về nhiều kết quả.

Điều này là không mong muốn vì

  1. Tập kết quả của bạn sẽ lớn hơn mức cần thiết, sẽ sử dụng nhiều bộ nhớ hơn mức cần thiết. Đặc biệt là như vậy nếu bạn có một hàng tồn kho rất lớn của hàng ngàn mặt hàng.
  2. Bạn sẽ cần thực hiện một kiểm tra bổ sung trong PHP để xác định xem kết quả có phải là dương tính giả hay không (ví dụ in_array($categoryThree, $product->getCategories()):), nghĩa là bạn sẽ lặp qua các kết quả không cần thiết. Điều này sẽ làm cho tập lệnh / mã của bạn chậm hơn, đặc biệt là với hàng tồn kho lớn.

Giải pháp

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

Truy vấn SQL được tạo sẽ trông như sau:

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

Giải trình:

Đưa ra sản phẩm và sản phẩm <=> bảng mối quan hệ danh mục:

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

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

Truy vấn của bạn có nội dung: "cung cấp cho tôi tất cả các hàng trong " catalog_product_entity " và dán vào cột" category_id "từ " catalog_carget_product " . Sau đó, chỉ cần đưa cho tôi các hàng category_id = 124" .

Bởi vì đó là một liên kết bên trái, nó sẽ luôn có các hàng từ "catalog_product_entity" . Đối với bất kỳ hàng nào không thể khớp, nó sẽ là NULL:

Kết quả +-------------+-------------+ | ENTITY_ID | CATEGORY_ID | +-------------+-------------+ | 423 | NULL | | 424 | 123 | | 425 | NULL | +-------------+-------------+

Từ đó, truy vấn sau đó nói, "ok, bây giờ hãy đưa cho tôi mọi thứ trong đó category_id là NULL" .


1

Không dễ dàng như nó có thể nhìn.

Dưới đây là tùy chọn dựa trên GROUP_CONCAT vì giới hạn mặc định của nó (dĩ nhiên là 1024 nhưng có thể tăng lên) sẽ ổn với các ID danh mục sản phẩm được phân tách bằng dấu phẩy.

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

Ngoài ra (nếu bạn không thích GROUP_CONCAT), bạn có thể sử dụng WHERE sản phẩm_ KHÔNG phải trong một truy vấn con của ID sản phẩm thực sự nằm trong các danh mục bạn cần loại trừ (không đưa ra ở đây).

Phương pháp chống tham gia từ một câu trả lời khác cũng sẽ hoạt động. Nhưng trong trường hợp này, bạn không thể dễ dàng thêm các điều kiện bổ sung.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.