2

I have this code but Anybody tell me faster way to update products.

This below code takes much time. So any alternative solution for to save product in fast way and Can I also put sleep function at end of the for loop to less consume memory ? Thank you

  public function updateProducts(){

        foreach($productIds as $productId){
            $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); // instance of object manager
            $product = $objectManager->create('\Magento\Catalog\Model\Product');
            $product->load($productId);
            $product->setSku('my-sku'); // Set your sku here
            $product->setName('Sample Simple Product'); // Name of Product
            $product->setStatus(1); // Status on product enabled/ disabled 1/0
            $product->setWeight(10); // weight of product
            $product->setVisibility(4); 
            $product->setPrice(100); // price of product
            $product->setStockData(
                                    array(
                                        'use_config_manage_stock' => 0,
                                        'manage_stock' => 1,
                                        'is_in_stock' => 1,
                                        'qty' => 14
                                    )
                                );
    $imageUrl = "https://example.com/img1.jpg";
    $tmpDir = $this->getMediaDirTmpDir();
    $newFileName = $tmpDir . baseName($imageUrl);
                        $result = $this->file->read($imageUrl, $newFileName);
                        if ($result) {
                             $_product->addImageToMediaGallery($newFileName,array('small','thumbnail','base'), $imageType, true, false);
                        }
            $product->save();
          unset($product);
        }
}
    protected function getMediaDirTmpDir(){
            return $this->directoryList->getPath(DirectoryList::MEDIA) . DIRECTORY_SEPARATOR . 'tmp';
        }
  • Why are you using object manager and why you put this in the loop. It will reduce speed. – Pushpendra Singh Jul 24 at 4:16
  • What are the best way to do import product , media images ? – Niraj Patel Jul 24 at 4:20
  • @NirajPatel Please check this blog post: czettner.com/2018/10/12/… – Bhaumik Upadhyay Jul 24 at 9:02
  • @NirajPatel What about Magmi? – zus Jul 24 at 10:46
  • @NirajPatel Are you able to update product details? I'm trying the same but name, description and some attributes are not updating – vartika sharma Jul 24 at 13:25
1
+200

I have a solution working on my local environment. Before posting the full solution, I'd like to verify your requirements:

  • we are after something that performs faster than your solution but you do not specify whether the speed is over 1 sku, many skus or 1000..

My import has pros and cons: I do not claim it competes with Magento and it is not ready for production as it is but it is not far off if you accept that some validations may go amiss..

  • for instance: I do not verify whether the sku in the import is unique

  • I assume it is fine to imagine the images may all be in pub/media/tmp/ folder

  • my import assigns random data only to the attributes that appear in your question (see below how these random data are generated) and therefore you understand in the real world you will have some csv parsing to do? Also, the data outside the scope of your data is not updated, or even set to a null value for instance.. (that means special_price might need work to do..)

    public function getStockData()
              {
                  return [
                      'use_config_manage_stock' => 0,
                      'manage_stock' => rand(0,1),
                      'is_in_stock' => rand(0,1),
                      'qty' => rand(1, 456)
                  ];
              }
    
              private function getProductRandomData(int $productId)
              {
                  return [
                      'sku' => sprintf('SKUBAT%s', $productId),
                      'name' => sprintf('Name for product %s', $productId),
                      'status' => rand(0,1),
                      'weight' => rand(1, 456),
                      'visibility' => rand(0, 4),
                      'price' => rand(3, 67)
                  ];
              } 
    
  • I do not validate the image extension but I create the image folders like Magento does.

  • finally, I do not use the product save function and that is why I am faster. Yet, I do run the indexes once the collection of products has been updated. That is why over 1 or 100 product, I may not be faster as the indexes will take a while to run. But over 10000, I will likely beat your script by couple of hours

In short, my solution is only as good as the time we have in a weekend and I hope you appreciate I have not come up with a genius script that outperforms years of work from Magento team.

If you could acknowledge the above is something that you have considered, I will post the solution.

https://bitbucket.org/magstaging/importbatchproduct/src

the above module has a command to run the product import.

php bin/magento mbs:import:product '1,2,3,4,5,6'

will import your data and images very fast, I'd say in 15 minutes for 10k but of course it depends on your server. But it will be definitely faster than your script as no product load is performed and no product save either.

It means unfortunately, the script may bypass plugin you may have on product save function for instance. But I can't read your system and I hope it will make your import happy..

| improve this answer | |
  • @HerveTribouuilloy In my case daily I am updating 10k products daily so I need optimize solution for that and stock data is key point to update data in fast manner. So Daily I am updating 10k products all attributes ,images(delete old one and insert new) and stock data. I am curious to know about your optimize solution.I am waiting for solution.Thank you – Niraj Patel Jul 26 at 5:21
  • And I am updating products from REST API .I checked that My API responses is fast and I am using dedicated server – Niraj Patel Jul 26 at 5:25
  • I will push a few more tests and then will post it, thanks for the update – Herve Tribouilloy Jul 26 at 6:52
  • Ok no problem thanks – Niraj Patel Jul 26 at 12:22
2

In order to update product attribute programmatically I use below way which is much faster then to save whole object

public function __construct(
.....
    \Magento\Catalog\Model\ResourceModel\Product\Action $productAction,
    ......  
) {
    $this->productAction = $productAction;
}



public function saveProductAttribute()
{
    $cnt = 0;
    
        try{

            $product = $this->productRepository->get($sku,false, null,true);
            if ($product->getSku()) {
                $updateAttributes['attribute_code1']  = $value1;
                $updateAttributes['attribute_code2']  = $value2;
                $updateAttributes['attribute_code3']  = $value3;
                $updateAttributes['attribute_code4']  = $value4;
                $updateAttributes['attribute_code5']  = $value5;
                $updateAttributes['attribute_code6']  = $value6;
                $updateAttributes['attribute_code7']  = $value7;
                $updateAttributes['attribute_code8']  = $value8;
                // in below code 0 is store Id 
                $this->productAction->updateAttributes([$product->getId()], $updateAttributes, 0);
                $cnt++;
            }
        } catch (\Exception $e){

        }
    
    return $this;
}
| improve this answer | |
1

I answered a similar question on this ticket, you can create a command import by using the default Magento import model.

That means you can use Magento import template CSV file like UI at System -> Data Transfer -> Import / Export

Ref: https://magento.stackexchange.com/a/318174/85035

Let me know if you need a more detailed script.

Thanks

| improve this answer | |
1

If you using console command for this propose that is very fast an useful things. For console command you need to do this below code. In between you have to put the product update csv in var/upload/ folder or you select other folder.

  1. add below code in di.xml file in app\code[Vendor][Namespace]\etc
<?xml version="1.0"?>
    <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
        <type name="Magento\Framework\Console\CommandList">
            <arguments>
                <argument name="commands" xsi:type="array">
                    <item name="bulk_product_update" xsi:type="object">[Vendor]\[Namespace]\Console\Command\UpdateProduct</item>
                </argument>
            </arguments>
        </type>
    </config>
  1. Create UpdateProduct.php in [Vendor][Namespace]\Console\Command
<?php

    namespace [Vendor]\[Namespace]\Console\Command;

    use \Symfony\Component\Console\Command\Command;
    use \Symfony\Component\Console\Input\InputInterface;
    use \Symfony\Component\Console\Output\OutputInterface;

    class UpdateProduct extends Command
    {
        public function __construct(
         \Magento\Store\Model\StoreManagerInterface $storeManager,
         \Magento\Catalog\Model\ResourceModel\Product\Action $productAction,
         \Magento\Catalog\Model\ProductFactory $productFactory,
         \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
         \Magento\Framework\File\Csv $csv,
         \Magento\Framework\Filesystem\Driver\File $fileDriver,
         \Magento\Framework\Filesystem\DirectoryList $dir,
         \Magento\Framework\Filesystem\Io\File $file
       )
       {
        $this->storeManager = $storeManager;
        $this->productAction = $productAction;
        $this->productFactory = $productFactory;
        $this->stockRegistry = $stockRegistry;
        $this->csv = $csv;
        $this->fileDriver = $fileDriver;
        $this->dir = $dir;
        $this->file = $file;
        parent::__construct();
      }

        protected function configure()
        {
            $this->setName('bulk:productupdate')
                 ->setDescription('Bulk product update with stock & Images');

            parent::configure();
        }

        protected function execute(InputInterface $input, OutputInterface $output)
        {
          $csvFilePath = $this->dir->getPath('var').'/upload/product_data.csv';
           if (!$this->fileDriver->isExists($csvFilePath)) {
                throw new \Magento\Framework\Exception\LocalizedException(__('Invalid file upload attempt.'));
           }

        $storeIds = array_keys($this->storeManager->getStores());
        $csvData = $this->csv->getData($csvFilePath);
        $attributeArray = array();
        foreach ($csvData as $row => $data) {
           if ($row > 0){
             
            $product = $this->productFactory->create()->load($data[$attributeArray['id']]);
           
            if(isset($data[$attributeArray['qty']])) {
                $stockData =  array(
                                        'use_config_manage_stock' => $data[$attributeArray['use_config_manage_stock']],
                                        'manage_stock' => $data[$attributeArray['manage_stock']],
                                        'is_in_stock' => $data[$attributeArray['is_in_stock']],
                                        'qty' => $data[$attributeArray['qty']]
                                    );
               $stockItem = $this->stockRegistry->getStockItem($data[$attributeArray['id']]); 
               $stockItem->setData($stockData);
               $stockItem->save(); 
           }

           $updateAttributes['sku'] = $data[$attributeArray['sku']];
           $updateAttributes['name'] = $data[$attributeArray['name']];
           $updateAttributes['status'] = $data[$attributeArray['status']];
           $updateAttributes['weight'] = $data[$attributeArray['weight']];
           $updateAttributes['visibility'] = $data[$attributeArray['visibility']];
           $updateAttributes['price'] = $data[$attributeArray['price']];

           foreach ($storeIds as $storeId) {
                $this->productAction->updateAttributes([$data[$attributeArray['id']]], $updateAttributes, $storeId);
           }

           if (isset($data[$attributeArray['image']])) {
               $imageUrl = $data[$attributeArray['image']];
               $newFileName = $this->dir->getPath('media'). '/tmp/' . baseName($imageUrl);
               $result = $this->file->read($imageUrl, $newFileName);
               if ($result) {
                             $_product->addImageToMediaGallery($newFileName, array('small','thumbnail','base'), true, false);
              }
           }
           $product->save();
           $output->writeln('Update Complete Product: '.$data[$attributeArray['sku']]);

        }
           } else {
             foreach($data as $key => $dataValue) {
                 $attributeArray[$dataValue] = $key;
             }
           }
        }


            $output->writeln('All product Update complete');
        }
    }

At last you need to run in terminal below command:

bin/magento bulk:productupdate

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.