PHP вставка из данных JSON в MySQL сверху вниз в то время как - PullRequest
0 голосов
/ 10 октября 2018

У меня проблема - мне нужно вставить данные из json в mysql, но он вставляет последний videoId и вставляет 3 одинаковых videoId 7EDPROQa4i0.Мне нужно вставить сверху вниз из JSON в базу данных.Я не могу понять, что не так

База данных JSON

{
  "resultsPerPage": 3
 },
 "items": [
  {
   "id": {
    "videoId": "kHPqpxDE50c"
   },
   "snippet": {
    "channelId": "UCiP20o92_7jUYwj-ulVLifw",
    },
   }
  },
  {
   "id": {
    "videoId": "DbAlCl3kk-M"
   },
   "snippet": {
    "channelId": "UCiP20o92_7jUYwj-ulVLifw",
    },
   }
  },
  {
   "id": {
    "kind": "youtube#video",
    "videoId": "7EDPROQa4i0"
   },
   "snippet": {
    "channelId": "UCiP20o92_7jUYwj-ulVLifw",
    },
   }
  }
 ]
}

КОД PHP:

    $loop = mysqli_query($conn, "SELECT channelid, videoId FROM users ORDER BY id")
    or die (mysqli_error($conn));

    while ($row = mysqli_fetch_array($loop))
    {
        $url = 'https://www.googleapis.com/youtube/v3/search?order=date&part=snippet&channelId='.$row['channelid'].'&maxResults=3&key=KEY';
        $content = file_get_contents($url);
        $json = json_decode($content, true);

        foreach($json['items'] as $row)
        {
            $channelid = $row['snippet']['channelId'];
            $videoId = $row['id']['videoId'];
            $videoId1 = $row['id']['videoId'];
            $videoId2 = $row['id']['videoId'];
            $sql = "INSERT INTO users(channelid, videoId, videoId1, videoId3) VALUES('$channelid', '$videoId', '$videoId1', '$videoId2')    
            ON DUPLICATE KEY UPDATE channelid='$channelid', videoId='$videoId', videoId1='$videoId1', videoId2='$videoId2';
            ";
            mysqli_query($conn, "SET NAMES utf8");
            if(!mysqli_query($conn,$sql))
            {
                die('Error : ' . mysqli_error($conn));
            }
        }
    }
$conn->close();
?>

1 Ответ

0 голосов
/ 11 октября 2018

Вот ваша проблема

foreach($json['items'] as $row){
    ...
    $videoId = $row['id']['videoId'];
    $videoId1 = $row['id']['videoId'];
    $videoId2 = $row['id']['videoId'];
     $sql = "INSERT INTO users(channelid, videoId, videoId1, videoId3) VALUES('$channelid', '$videoId', '$videoId1', '$videoId2')    
        ON DUPLICATE KEY UPDATE channelid='$channelid', videoId='$videoId', videoId1='$videoId1', videoId2='$videoId2';
        ";
    ...
}

В основном, что происходит, это взять ваши первые данные JSON (я сосредоточусь только на части значений):

 //iteration 1
 VALUES('UCiP20o92_7jUYwj-ulVLifw', 'kHPqpxDE50c', 'kHPqpxDE50c', 'kHPqpxDE50c')
//iteration 2
 VALUES('UCiP20o92_7jUYwj-ulVLifw', 'DbAlCl3kk-M', 'DbAlCl3kk-M', 'DbAlCl3kk-M')
//iteration 3
 VALUES('UCiP20o92_7jUYwj-ulVLifw', '7EDPROQa4i0', '7EDPROQa4i0', '7EDPROQa4i0')

Теперь подумайте, что происходит,Из-за того, как настроена ваша таблица (я могу добавить неправильно), я бы поспорил, что chanelid уникально.Таким образом, каждый цикл, который вы перезаписываете идентификаторы из предыдущего цикла.

это 3 одинаковых videoId, вставляющих 7EDPROQa4i0

Что, кстати, и есть "Точно", что вы видите.

Чтобы исправить это, вы должны вставить / обновить после цикла JSON.Создав массив видео идентификаторов, которые мы можем вставить в один запрос.Вам не нужен 1 запрос для каждого цикла данных JSON (способ его настройки).

Пример:

$loop = mysqli_query($conn, "SELECT channelid, videoId FROM users ORDER BY id")
or die (mysqli_error($conn));

while ($row = mysqli_fetch_array($loop))
{
    $channelid = $row['channelid'];
    $url = 'https://www.googleapis.com/youtube/v3/search?order=date&part=snippet&channelId='.$channelid .'&maxResults=3&key=KEY';
    $content = file_get_contents($url); 
    $json = json_decode($content, true);    

    if(!isset($json['items'])) continue; //skip if no items

    $videos = ['videoId'=>'','videoId1'=>'','videoId2'=>''];
    $i = 0;
    foreach($json['items'] as $items)
    {
        $key  = 0==$i ? 'videoId' : 'videoId'.$i;
        $videos[$key] = $items['id']['videoId']; 
        ++$i;
    }

    $sql = "INSERT INTO users(channelid, videoId, videoId1, videoId3) VALUES('$channelid', '{$videos['videoId']}', '{$videos['videoId1']}', '{$videos['videoId2']}')    
        ON DUPLICATE KEY UPDATE channelid=VALUES(channelid), videoId=VALUES(videoId), videoId1=VALUES(videoId1), videoId2=VALUES(videoId2);
        ";
    mysqli_query($conn, "SET NAMES utf8");
    if(!mysqli_query($conn,$sql))
    {
        die('Error : ' . mysqli_error($conn));
    }
}

Это решает непосредственную проблему.Однако здесь есть гораздо более серьезная проблема: как настраивается ваша таблица и как вы ее используете.То, как у вас это получается, вы ограничены только 3 видео, и даже если это все, что вам нужно, в какой-то момент вам может понадобиться больше.Каждый всегда хочет большего, это данность.Чтобы обновить его, чтобы иметь 4, 5 или 6, необходимо добавить дополнительные столбцы, что плохо.

Более глубокие проблемы

Лучший способ - использовать 1 строку навидео.Так как мы это сделаем?

Первое, что нужно сделать, это экспортировать эту таблицу (таким образом, у вас есть резервная копия)

Затем измените индекс для channelid на составной (составной) «Уникальный» индекс, который имеет 2поля channelid и videoId в качестве полей.Оба они должны быть одинаковыми, чтобы строка считалась дубликатом.

Затем добавьте простой (неуникальный) индекс обратно на channelId.Вы хотите, чтобы у него был свой собственный индекс, потому что для того, чтобы составной работал нормально, вы не захотите указывать оба поля (в порядке индекса).Тем не менее, я забыл (между БД и некоторыми другими вещами, такими как Монго), так что вы можете использовать один, если он первый.Вы всегда можете объяснить и убедиться, что он его использует.В любом случае, вы хотите этот индекс, потому что мы собираемся использовать его для поиска, и хорошая индексация - это хорошо.

Далее вам придется полностью избавиться от videoId1 и videoId2.Если у вас есть данные, которые вы не хотите потерять, вы можете создать скрипт миграции, который извлечет значения из этих двух полей и создаст для них новую строку.

Затем в код.

$loop = mysqli_query($conn, "SELECT DISTINCT channelid FROM users ORDER BY id")
or die (mysqli_error($conn));

while ($row = mysqli_fetch_array($loop))
{
    $channelid = $row['channelid'];
    $url = 'https://www.googleapis.com/youtube/v3/search?order=date&part=snippet&channelId='.$channelid .'&maxResults=3&key=KEY';
    $content = file_get_contents($url);
    $json = json_decode($content, true);

    if(!isset($json['items'])) continue; //skip if no items

    foreach($json['items'] as $items)
    {
        $videoId = $items['id']['videoId'];
        $sql = "INSERT INTO users(channelid, videoId) VALUES('$channelid', '$videoId')    
        ON DUPLICATE KEY UPDATE channelid=VALUES(channelid), videoId=VALUES(videoId);
        ";
        mysqli_query($conn, "SET NAMES utf8");
        if(!mysqli_query($conn,$sql))
        {
            die('Error : ' . mysqli_error($conn));
        }
    }
}

Это намного ближе к вашему оригиналу, но мы используем только одно поле в первом запросе и DISTINCT.Остальное должно быть самоочевидным.

Когда вы извлекаете данные, вам просто нужно зациклить результаты, поскольку в каждой строке будет 1 видео.В долгосрочной перспективе это упростит задачу, обещаю.

Другие вещи

У вас также есть проблемы с SQL-инъекцией, которые могут быть менее взломаны,но зачем рисковать.Каждый раз, когда вы объединяете данные в запрос, вы открываете дверь SQLInjection.Даже если данные на 100% безопасны, вы ничего не потеряете, всегда готовя свои запросы.Существует множество учебных пособий о том, как это сделать.

Вы можете использовать VALUES(column) в дубликате, что я и сделал.Это избавляет нас от необходимости дублировать переменную (чего не должно быть здесь), но даже когда вы ее подготовите, это облегчит задачу.

Соглашения об именах, такие как channelid против videoId против channelId.Может показаться, что это не имеет большого значения, но это действительно так.В то время как у каждого есть свой собственный способ сделать это, самая важная часть - быть последовательным.Я предпочитаю без заглавных букв, подчеркивания для пробелов, имена таблиц во множественном числе.Так что для меня это будет channel_id, video_id.Зная это и будучи непротиворечивым, мне не нужно оглядываться на схему таблицы, которую я сделал год назад, и спрашивать себя: channelid, ChannelId, channelID, channelId или channel_id.КАК вы можете видеть, просто посмотрев, есть больше вариаций в корпусных версиях, чем в строчной версии (4+ против 2).Пробелы в имени столбца не являются начальными в MySQL, так как вы должны избегать их с помощью backtics, так что это никогда не будет вопросом.

Вы перезаписывали переменную $row во внутреннем цикле, для JSON, поэтому я изменил ее на $items.Вам также не нужен channelid из JSON, потому что он уже есть в запросе (и в URL).

Наслаждайтесь!

...