Here's the outline for database tables and processing a Product Set update in order to prevent duplicate product entries (because of a race condition occurring).
Our main table with be datafeedr_productset_record_join
It will contain the following schema:
--
-- Table structure for table `datafeedr_productset_record_join`
--
CREATE TABLE `datafeedr_productset_record_join` (
`id` int(20) UNSIGNED NOT NULL,
`product_set_id` int(20) UNSIGNED NOT NULL,
`record_id` bigint(20) UNSIGNED NOT NULL,
`post_type` varchar(50) NOT NULL,
`action` varchar(50) NOT NULL,
`status` int(1) UNSIGNED NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Dumping data for table `datafeedr_productset_record_join`
--
INSERT INTO `datafeedr_productset_record_join`
(`id`, `product_set_id`, `record_id`, `post_type`, `action`, `status`)
VALUES
(1, 123, 3273500000006527, 'product', 'update', 0),
(2, 123, 3273500000018502, 'product', 'update', 0),
(3, 123, 3273500000018503, 'product', 'create', 0),
(4, 123, 3273500000018504, 'product', 'create', 0);
--
-- Indexes for dumped tables
--
--
-- Indexes for table `datafeedr_productset_record_join`
--
ALTER TABLE `datafeedr_productset_record_join`
ADD PRIMARY KEY (`product_set_id`,`record_id`),
ADD UNIQUE KEY `record_id` (`record_id`,`post_type`),
ADD KEY `id` (`id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `datafeedr_productset_record_join`
--
ALTER TABLE `datafeedr_productset_record_join`
MODIFY `id` int(20) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5;
In the table, action
is what we need to do with the product and status
indicates what we have done.
Example: action=create
& status=0
This means we will be creating a new product in WordPress but we have not done so yet.
action=create, status=0 - A product should be created but has not yet been created.
action=create, status=1 - A product has been created.
action=update, status=0 - A product should be updated but has not yet been updated.
action=update, status=1 - A product has been updated.
action=delete, status=0 - A product should be deleted but has not yet been deleted.
action=delete, status=1 - A product has been deleted.
This will also allow accurate stats tracking for a Product Set update making it easy for us to capture how many products were added, updated and deleted.
Additionally, it will make it really easy to find all of the products which need to be deleted. Just a simple:
SELECT *
FROM datafeedr_productset_record_join
WHERE product_set_id = $this_product_set_id
AND action = 'delete'
AND status = 0
1. Start Update
When we start a Product Set update, first we will issue an UPDATE
query on the datafeedr_productset_record_join
table setting status
equal to 0
for the current Product Set and if the action
= update
.
UPDATE datafeedr_productset_record_join
SET
action = 'update',
status = 0
WHERE product_set_id = $this_product_set_id
2. Add Datafeedr records to tables
Next, we'll query all of the products in the Product Set from the Datafeedr API and INSERT
the products into the datafeedr_records
table.
- `INSERT ... ON DUPLICATE KEY UPDATE` all products into the `datafeedr_products` table
- Then we'll do a query like this to add all NEW products into the
INSERT IGNORE INTO datafeedr_productset_record_join
( product_set_id, record_id, post_type, action, status )
VALUES
( 123, 3273500000006527, 'product', 'create', 0 ),
( 123, 3273500000018502, 'product', 'create', 0 ),
( 123, 3273500000018503, 'product', 'create', 0 ),
( 123, 3273500000018504, 'product', 'create', 0 ),
( 123, 3273500000018503, 'product', 'create', 0 )
3. Now we can perform quick queries to import the data like this:
Next we can issue this query in a loop to import products into WordPress:
// Get a row from productset_record_join to add to WordPress
// @link https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
// @link https://dba.stackexchange.com/questions/46459/putting-a-select-statement-in-a-transaction
// @link https://dba.stackexchange.com/questions/182963/can-two-mysql-select-for-update-from-mytable-where-in-deadlock
START TRANSACTION;
SELECT @id := id FROM datafeedr_productset_record_join
WHERE action IN ( 'create', 'update' )
AND status = 0
ORDER BY id ASC
LIMIT 1
FOR UPDATE;
// Get the record data
$record = SELECT data FROM datafeedr_records WHERE id = $row->id LIMIT 1;
// Insert or Update Post
if ( 'create' == $row->action ) {
$post_id = wp_insert_post( $record data );
} else {
$post_id = wp_update_post( $record data );
}
// Update datafeedr_productset_record_join
UPDATE datafeedr_productset_record_join
SET status = 1
WHERE id = @id;
COMMIT;