Pregunta

Aquí está mi código:

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

Quiero obtener todos los productos que no están en la lista de ID de categoría, pero mi código no dio el resultado esperado. Por favor, muéstreme el camino, gracias.

¿Fue útil?

Solución

Debe unirse a la tabla que contenga las relaciones de categoría/producto.

Una variación de la colección que utilizo para encontrar todos los productos en una lista de categorías debe hacer el truco por usted:

(no probado, pero debería llevarlo en el camino correcto)

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

árbitro: http://www.proxiblue.com.au/blog/collection_of_products_in_all_child_categories/

Otros consejos

El siguiente código funcionará para usted:

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

He encontrado una manera algo mejor de hacer esto, usando un anti-unión (Magento 1.9).

Beneficios de este enfoque

El beneficio de esto sobre la respuesta original es que no obtendrá falsos positivos, y es más rápido y menos propenso a errores. Por ejemplo, suponga que tiene un solo producto:

  1. Camisa (en categorías: 1 | 2)

Tú quieres "Encuentra todos los productos que no están en category 3, luego agrégalos a category 3". Entonces corres un NOT IN consulta, y devolverá dos filas (name | category_id):

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

No es gran cosa, Magento solo devolverá el primer resultado, y luego lo agrega. Excepto! La segunda vez que se ejecuta esta consulta, tiene los mismos resultados:

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

Y Magento te dirá que todavía no has agregado esta camisa a category 3. Esto se debe a que cuando un producto pertenece a múltiples categorías, tendrán múltiples filas en el "catáloga_product_entity" mesa. Y así un LEFT JOIN devolverá múltiples resultados.

Esto es indeseable porque

  1. Su conjunto de resultados será más grande de lo necesario, lo que utilizará más memoria de la necesaria. Especialmente si tiene un inventario muy grande de miles de artículos.
  2. Deberá hacer una verificación adicional en PHP para determinar si los resultados son falsos positivos (por ejemplo, in_array($categoryThree, $product->getCategories())), lo que significa que pasarás a través de resultados innecesarios. Esto hará que su script/código sea más lento, especialmente con grandes inventarios.

Solución

// 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 consulta SQL generada se verá como:

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

Explicación:

Dado el producto y el producto <=> Tablas de relación de categoría:

catáloga_product_entity +-----------+ | ENTITY_ID | +-----------+ | 423 | | 424 | | 425 | +-----------+

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

Tu consulta dice: "Dame todas las filas en "catáloga_product_entity", y pegar en la columna "Categy_id" de "catáloga_category_product". Entonces solo dame las filas que Category_id = 124 ".

Porque es una unión a la izquierda, siempre tendrá las filas de "catáloga_product_entity". Para cualquier fila que no se pueda combinar, será NULL:

Resultado +-------------+-------------+ | ENTITY_ID | CATEGORY_ID | +-------------+-------------+ | 423 | NULL | | 424 | 123 | | 425 | NULL | +-------------+-------------+

A partir de ahí, la consulta dice: "Ok, ahora dame todo donde la categoría_id es nula".

No es tan fácil como puede verse.

Aquí está la opción basada en Group_concat, ya que es el límite predeterminado (1024 pero podría aumentarse, por supuesto) debería estar de acuerdo con las ID de categoría de productos separadas por el conjunto de comas.

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

Además (si no le gusta group_concat), puede usar dónde product_id no en una subconsulta de una identificación de producto está realmente en categorías que necesita excluir (no darlo aquí).

Enfoque anti-unión de otro responder También funcionará. Pero en este caso no puede agregar fácilmente condiciones adicionales.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a magento.stackexchange
scroll top