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:
- Á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 IN
truy 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 JOIN
sẽ trả về nhiều kết quả.
Điều này là không mong muốn vì
- 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.
- 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" .