Question

Voici mon code:

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

Je veux obtenir tous les produits non dans la liste de catégorie mais ids mon code n'a pas donné le résultat escompté. S'il vous plaît me montrer le chemin, merci.

Était-ce utile?

La solution

Vous devez joindre à la table qui contient la catégorie / relations produit.

Une variante de la collection que j'utilise pour trouver tous les produits dans une liste de catégories devrait faire l'affaire pour vous:

(non testé, mais devrait vous mettre dans la bonne voie)

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

Autres conseils

code suivant fonctionnera pour vous:

$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('*');

Je l'ai trouvé d'une manière un peu mieux de le faire, à l'aide d'un anti-join (Magento 1.9).

Les avantages de cette approche

L'avantage de ce sur la réponse initiale est que vous ne serez pas faux positifs, et il est plus rapide et moins sujette aux erreurs en conséquence. Par exemple, supposons que vous avez un seul produit:

  1. Shirt (dans les catégories: 1 | 2)

Vous voulez "trouver tous les produits non category 3, puis les ajouter à category 3" . Donc, vous exécutez une requête NOT IN, et il va revenir deux lignes (name | category_id):

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

Pas grand-chose, Magento toujours revenir seulement le premier résultat, puis vous ajoutez. Sauf ! La deuxième fois cette requête s'exécuter, vous avez les mêmes résultats:

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

Et Magento vous dira que vous avez pas encore ajouté cette chemise à category 3. En effet, lorsqu'un produit appartient à plusieurs catégories, ils ont plusieurs lignes dans la « catalog_product_entity » tableau . Et donc un LEFT JOIN retournera plusieurs résultats.

Ceci est indésirable parce que

  1. Vos résultats sera plus grande que nécessaire, qui utilisera plus de mémoire que nécessaire. Surtout si vous avez un inventaire très grand nombre de milliers d'articles.
  2. Vous devrez faire une vérification supplémentaire en PHP pour déterminer si les résultats sont faux positifs (par exemple, in_array($categoryThree, $product->getCategories())), ce qui signifie que vous aurez une boucle à travers les résultats inutiles. Cela rendra votre script / code plus lent, en particulier avec des stocks importants.

Solution

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

La requête SQL généré ressemblera à:

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

Explication:

Compte tenu des produits et des produits de tables catégorie <=> relation:

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

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

Votre requête dit, "me donner toutes les lignes de " catalog_product_entity " et coller sur la "category_id" colonne de " catalog_category_product ". Ensuite, il suffit donnez-moi les lignes category_id = 124" .

Parce qu'il est une jointure gauche, ça va toujours les lignes de « catalog_product_entity » . Pour toutes les lignes qui ne peut être apparié, ce sera NULL:

Résultat +-------------+-------------+ | ENTITY_ID | CATEGORY_ID | +-------------+-------------+ | 423 | NULL | | 424 | 123 | | 425 | NULL | +-------------+-------------+

A partir de là, la requête dit alors, "ok, donnez-moi maintenant tout où le category_id est NULL" .

Pas aussi facile que cela puisse paraître.

Voici la GROUP_CONCAT comme l'option à base de limite par défaut (1024, mais pourrait être augmentée bien sûr) doit être d'accord avec les ID de catégorie de produits séparés par des virgules jeu.

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

De plus (si vous ne le faites pas comme GROUP_CONCAT) vous pouvez utiliser OÙ product_id PAS une sous-requête d'un ID de produit sont effectivement dans les catégories que vous devez exclure (ne donnant pas ici).

approche

Anti-join d'une autre répondre travaillera également. Mais dans ce cas, vous ne pouvez pas facilement ajouter des conditions supplémentaires.

Licencié sous: CC-BY-SA avec attribution
Non affilié à magento.stackexchange
scroll top