Я прочитал почти все темы о создании URL-адреса из (или загрузки) BLOB-объекта на компьютере, однако мне нужно что-то другое:
(1) сохранить большой двоичный объект на собственном сервере в файл JSON, затем
(2) оптимизировать способ обновления базы данных с использованием данных, хранящихся в JSON.
Я пробовал все варианты кода ниже без успеха
var blob = new Blob(response, { type: contentType });
var file = new File([blob], filename, {type: contentType, lastModified: Date.now()});
где ответ был parsedJSON из приведенного ниже кода.
Было бы лучше вместо этого иметь файл с пустым содержимым на сервере, открыть его и обновить из большого двоичного объекта (затем закрыть его)?
Моя цель - загрузить содержимое ответа из запроса AJAX (из API) на мой сервер (а не на какой-либо клиентский компьютер в браузере), а затем обновить соответствующие значения в таблице базы данных.
Вариант использования следующий: я получаю прайс-лист (около 40 000 позиций) из API с помощью cron, затем мне нужно обновить цены на продукты в базе данных на моем сервере.
Давайте посмотрим на код ниже:
<div id="app">
<p style="text-align: center; margin-top: 50px;">
<i class="fa fa-spinner fa-spin" style="font-size: 15px;"></i><br>
please wait to load the list of items here...
</p>
</div>
<script>
var settings = {
"url": "https://www.notimportant/etc/",
"method": "GET",
"timeout": 0,
"headers": {
"GUID": "something"
},
};
$.ajax(settings).done(function(response) {
var parsedJSON = JSON.parse(response);
console.log(parsedJSON[0]); /* <= to see the structure of each object in the response array */
console.log('total items: ' + parsedJSON.length);
var template = `
<p>List of items</p>
{{#each this}}
<div>{{plusOne @index}} - Code: {{ProductCode}} - Name: {{ProductName}} - Price: {{ProductPrice}}</div>
{{/each}}
`;
Handlebars.registerHelper('plusOne', function(index) {
index++;
return index;
});
var show = Handlebars.compile(template);
$('#app').html(show(parsedJSON));
});
</script>
Пока все хорошо, я мог проверить с помощью Handlebars JS результаты в браузере (и также увидеть в консоли структуру объекта, полученную от API). Однако моя цель — использовать каждый объект из массива parsedJSON для обновления значений в таблице. Я мог бы сделать что-то вроде
for(i = 0; i < parsedJSON.length; i++) { // use here $.post to send ProductCode, ProductName and ProductPrice to a php file where I execute a query to update each product into the database
var ProductCode = parsedJSON[i].ProductCode;
var ProductName = parsedJSON[i].ProductName;
var ProductPrice = parsedJSON[i].ProductPrice;
$.post("update_db.php", {code: ProductCode, name: ProductName, price: ProductPrice}, function(data, status){
console.log("Product " + ProductCode + " update = " + status);
});
}
alert("all products' update was finished");
однако это создаст ~ 40 000 одиночных запросов в мою базу данных (что совсем не нормально).
Вместо этого я бы предпочел сохранить массив на сервере (чтобы сохранить большой двоичный объект ответа, создайте из него файл, назовите его myJSONfile.json, затем в php используйте $myfileaddress = $base + "myJSONfile.json"
, прочитать его с помощью $myfile = file_get_contents($myfileaddress)
, затем $myJson = json_decode($myfile, true)
, а затем обновить базу данных с помощью foreach($array as $item) {// update each row in products table in database
и т. д. }
Однако я сомневаюсь, что смогу запустить множественный запрос с 40 000 компонентов (или подготовленный оператор такого большого размера, даже если я значительно увеличу разрешенную память - я бы предпочел этого не делать). Если я ошибаюсь, объясните мне, почему.
На данный момент мой код просто отправляет запросы один за другим, что я бы не стал делать (мне лучше использовать только php или только JavaScript, чтобы создать одно соединение с БД, а не много на данный момент) .
На самом деле я получаю почти мгновенный ответ - предупреждение обновление всех продуктов было завершено для полного списка продуктов, но затем ответные сообщения php также продолжают поступать в консоль в течение довольно долгого времени об успешном обновлении. каждую строку (разговор о нескольких минутах), чего я не ожидал.
Я бы использовал что-то элегантное, скажем, использовать 500 запросов в одной транзакции (и сделать все обновление всего за 80 шагов вместо полных 40 000 простых запросов), но не уверен, как все правильно настроить.
Моя точка зрения на загрузку полного JSON вместо обновления каждого продукта через отдельный запрос API (плюс обновление) заключается в том, чтобы запросить внешний сервер только один раз (используя cron), а не много раз, и выполнить дальнейшую обработку данных в моем собственном сервер вместо этого. В реальной ситуации каждый товар поступает из API с примерно 20 параметрами, а не только с 3 (Код, Название и Цена), но это не имеет отношения к рассматриваемым вопросам. (Кроме того, извините за некоторые небольшие небрежности в коде, показанном в отдельных фрагментах, но я быстро набирал вместо каких-либо копипастов из производственных файлов - я сейчас не пишу с компьютера, на котором я работаю над рассматриваемым проектом).
Окончательное редактирование
Наконец, я написал приведенный ниже более компактный код, который отлично работает (подготовленный оператор с UPDATE). Вместо того, чтобы публиковать его как отдельный ответ, я вставлю его здесь:
<?php
$servername = "localhost";
$username = "someuser";
$password = "somepassw";
$dbname = "somedb";
// requiring data from API
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://www.notimportant/etc/",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS =>"{\"name\": null, \"stores\": null, \"products\": []}",
CURLOPT_HTTPHEADER => array(
"GUID: something",
"Content-Type: application/json"
),
));
$response = curl_exec($curl);
curl_close($curl);
// echo $response;
$data = json_decode($response);
echo "Product count: " . count($data) . "<br>\n";
echo "Preparing to save products to database... <br>\n";
// end receiving data from API
// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);
// Check connection
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// prepare and bind
$stmt = $conn->prepare("UPDATE `my_table` SET `price` = ?, `stock` = ? WHERE `my_table`.`product_id` = ?");
$stmt->bind_param("dii", $price, $stock, $id);
// set parameters and execute
foreach($data as $productInfo) {
$price = $productInfo->RetailPrice;
$stock = $productInfo->Stock;
$id = $productInfo->ProductId;
$stmt->execute();
}
echo "Update was ok";
$stmt->close();
$conn->close();
?>
Предложения @Bravemaster были полезны, теперь код выполняется менее чем за 10 секунд, так что на данный момент это приемлемое решение. Пункт (2) довольно решен, а (1) кажется бесполезным (поскольку нет смысла использовать и file_put_contents, и file_get_contents). Я также голосую за вклад Bravemaster как за принятый ответ - за его любезный вклад в мой код. Все 40 000+ запросов прошли гладко в одном пакете. Осталось добавить дополнительную проверку данных (чтобы быть в безопасности) и настроить процесс cron (на самом деле это не проблема).