I need to collect the data about the products which are bought together with the existing product on the store (in case there are any). The data should be taken from the table, storing the order items. I already have some workouts, but all of them seems to be awkward. It seems that there should be some simple and elegant way to get this data. Have someone already faced this task? Please, tell me in what way is it better to collect data about products crossing in Magento 2?
I have an array with product_id
on the input which was got from the collection of all the products:
/** @var \Magento\Catalog\Model\Product $product */
$productIds = $product->getCollection()
->addWebsiteFilter($website->getId())
->getAllIds();
Then I collect the data separately by all the products (by id) in the following way:
foreach ($productIds as $productId) {
$result = $this->collectNewDataForProduct($productId);
// save data...
}
In this method: collectNewDataForProduct
I collect an array with the products which encounter together with this product in the orders and the frequency of their encountering. I would like to modify this query or all the code (in case there is a good solution).
My workouts looks like this:
Query variation 1
SQL query:
SELECT
`main_table`.`product_id`,
(SUM(`main_table`.`product_id`) / `main_table`.`product_id`) AS `frequency`
FROM `sales_order_item` AS `main_table`
WHERE `main_table`.`order_id` IN
(SELECT `sub_table`.`order_id`
FROM `sales_order_item` AS `sub_table`
WHERE `sub_table`.`product_id` = 1)
AND
`main_table`.`product_id` != 1
GROUP BY `main_table`.`product_id`;
PHP code for this query:
protected function collectNewDataForProduct($productId)
{
$connection = $this->getResource()->getConnection();
$orderItemTable = $connection->getTableName('sales_order_item');
$select = $connection->select();
$subSelect = clone $select;
$subSelect->from(['sub_table' => $orderItemTable], ['order_id']);
$subSelect->where('`sub_table`.`product_id` = ' . $productId);
$sum = new \Zend_Db_Expr('(SUM(`main_table`.`product_id`)/`main_table`.`product_id`)');
$select->from(['main_table' => $orderItemTable], ['product_id', 'frequency' => $sum]);
$select->where('`main_table`.`order_id` IN (' . $subSelect->__toString() . ')');
$select->where('`main_table`.`product_id` != ' . $productId);
$select->group('main_table.product_id');
$result = $connection->fetchAll($select);
return $result;
}
Query variation 2
SQL query:
SELECT
`sub_table`.`product_id`,
SUM(sub_table.qty)
FROM `sales_order_item` AS `main_table`
LEFT JOIN `sales_order_item` AS `sub_table`
ON (main_table.order_id = sub_table.order_id AND main_table.product_id != sub_table.product_id)
WHERE main_table.product_id = 1
GROUP BY `sub_table`.`product_id`;
PHP code for this query:
$sum = new \Zend_Db_Expr('(SUM(`main_table`.`product_id`)/`main_table`.`product_id`)');
/** $this->orderItem instance of \Magento\Sales\Model\Order\Item */
$collection = $this->orderItem->getCollection()
->addFieldToSelect(['product_id', 'frequency' => $sum])
->removeFieldFromSelect('item_id');
$select = $collection->getSelect();
$connection = $collection->getConnection();
$orderItemTable = $connection->getTableName('sales_order_item');
$select->joinLeft(
['sub_table' => $orderItemTable],
'`main_table`.`order_id` = `sub_table`.`order_id` AND `main_table`.`product_id` != `sub_table`.`product_id`',
['product_id']
);
$collection->addFieldToFilter('main_table.product_id', ['eq' => $productId]);
$select->group('sub_table.product_id');
As I've highlighted before, there variations seems to be not the best solutions and I want you to help me on how to improve the query/code in order to gain my aim.
Update:
With this code I am trying to count the product qty bought together with the product chosen (by id). For example: how many times the product A was bought with Product B. And the same with all the products, which exist in the sales_order_item
table.
The result looks approximately like this:
product_id_1 | product_id_1 | count
-----------------------------------
A | B | 10
A | C | 1
etc.
where the 1-st and 2-nd columns - are the product ids and the 3-d one is the coincidence qty by all the parameters.