{"id":3848,"date":"2021-12-16T14:32:01","date_gmt":"2021-12-16T14:32:01","guid":{"rendered":"http:\/\/truelogic.org\/wordpress\/?p=3848"},"modified":"2021-12-16T14:35:21","modified_gmt":"2021-12-16T14:35:21","slug":"convert-imdb-data-to-mysql-tables-using-c-part-1","status":"publish","type":"post","link":"https:\/\/truelogic.org\/wordpress\/2021\/12\/16\/convert-imdb-data-to-mysql-tables-using-c-part-1\/","title":{"rendered":"Convert IMDB data to MySql tables using C++ &#8211; Part 1"},"content":{"rendered":"\n<p><strong>OVERVIEW<\/strong><\/p>\n\n\n\n<p>IMDB , being the world&#8217;s best known and largest movie and TV website, does not provide any API to use their data. However , they provide datasets of their entire database in TSV files (tab separated values).  They contain all the data pertaining to movies, TV shows and their cast and ratings.<\/p>\n\n\n\n<p>The dataset can be downloaded from <a rel=\"noreferrer noopener\" aria-label=\"https:\/\/datasets.imdbws.com\/ (opens in a new tab)\" href=\"https:\/\/datasets.imdbws.com\/\" target=\"_blank\">https:\/\/datasets.imdbws.com\/<\/a> The files  can be converted into various formats and databases for any work to be done on them. The explanation of the format and fields are given here: <a rel=\"noreferrer noopener\" aria-label=\"https:\/\/www.imdb.com\/interfaces\/ (opens in a new tab)\" href=\"https:\/\/www.imdb.com\/interfaces\/\" target=\"_blank\">https:\/\/www.imdb.com\/interfaces\/<\/a> . This data dump is updated daily.<\/p>\n\n\n\n<p><strong>Please note that IMDB forbids any commercial usage of this data. It can be only used for personal and non-commercial use-cases.<\/strong><\/p>\n\n\n\n<p>In this blog series, we look at how to convert the tsv files into a normalized Mysql database. <\/p>\n\n\n\n<p>In Part 1 we will only capture all the raw data from the tsv files into mysql tables. In the next part we will look at adding indexes and optimizing the database to remove duplication and redundancy.<\/p>\n\n\n\n<p><strong>WHY C++<\/strong><\/p>\n\n\n\n<p>Processing the TSV files is not complex and can be done in any high level language like Python or Java or PHP. However, because the size of the files go into hundreds of Mb and a couple of Gb, it can take very long to process all the files. I used C++ because thats probably the fastest performance one can get . Even on an old Intel Core2Duo machine, each of the tsv files did not take longer than 10-15 minutes at the most.<\/p>\n\n\n\n<p><strong>OBJECTIVE OF PART 1<\/strong><\/p>\n\n\n\n<p>What we are doing here, is process each tsv file and create an sql file which contains INSERT statements for each tsv row. Then, each of these sql files is processed directly in MySQL. This is faster than trying to do a direct Mysql insert using C++ code.<\/p>\n\n\n\n<p>The code uses wxWidgets library for some of the functions. At some point in the future, I aim to make a GUI app to process and retrieve the mysql data so that is the reason why wxWidgets is part of the equation.<\/p>\n\n\n\n<p><strong>CODE SETUP<\/strong><\/p>\n\n\n\n<p>I am using this on Ubuntu but it can be easily run on Windows as well with minimal changes since I am using STL and wxWidgets which is cross-compatible with Unix, Windows and MacOS.<\/p>\n\n\n\n<p>To set up wxWidgets on Windows, take a look at <a rel=\"noreferrer noopener\" aria-label=\"https:\/\/truelogic.org\/wordpress\/2021\/12\/06\/setting-up-wxwidgets-environment-for-c-in-windows-10\/ (opens in a new tab)\" href=\"https:\/\/truelogic.org\/wordpress\/2021\/12\/06\/setting-up-wxwidgets-environment-for-c-in-windows-10\/\" target=\"_blank\">https:\/\/truelogic.org\/wordpress\/2021\/12\/06\/setting-up-wxwidgets-environment-for-c-in-windows-10\/<\/a><\/p>\n\n\n\n<p>To set up wxWidgets in Ubuntu or Debian Linux, take a look at <a rel=\"noreferrer noopener\" aria-label=\"https:\/\/truelogic.org\/wordpress\/2021\/10\/31\/setting-up-wxwidgets-environment-for-c-in-ubuntu-linux\/ (opens in a new tab)\" href=\"https:\/\/truelogic.org\/wordpress\/2021\/10\/31\/setting-up-wxwidgets-environment-for-c-in-ubuntu-linux\/\" target=\"_blank\">https:\/\/truelogic.org\/wordpress\/2021\/10\/31\/setting-up-wxwidgets-environment-for-c-in-ubuntu-linux\/<\/a><\/p>\n\n\n\n<p><strong>MYSQL TABLES<\/strong><\/p>\n\n\n\n<p>The mysql dump for the table structures is given below. This can be used to create the database<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\n-- Adminer 4.7.7 MySQL dump\n\nSET NAMES utf8;\nSET time_zone = &#039;+00:00&#039;;\nSET foreign_key_checks = 0;\nSET sql_mode = &#039;NO_AUTO_VALUE_ON_ZERO&#039;;\n\nDROP TABLE IF EXISTS `name_basics`;\nCREATE TABLE `name_basics` (\n  `ID` bigint(20) NOT NULL AUTO_INCREMENT,\n  `nconst` varchar(20) DEFAULT NULL,\n  `primaryName` varchar(255) DEFAULT NULL,\n  `birthYear` varchar(10) DEFAULT NULL,\n  `deathYear` varchar(10) DEFAULT NULL,\n  `primaryProfession` varchar(255) DEFAULT NULL,\n  `knownForTitles` text,\n  PRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n\n\nDROP TABLE IF EXISTS `title_akas`;\nCREATE TABLE `title_akas` (\n  `ID` bigint(20) NOT NULL AUTO_INCREMENT,\n  `titleid` varchar(20) NOT NULL,\n  `ordering` int(11) NOT NULL,\n  `title` varchar(255) CHARACTER SET utf8 NOT NULL,\n  `region` varchar(5) DEFAULT NULL,\n  `language` varchar(25) DEFAULT NULL,\n  `types` varchar(15) DEFAULT NULL,\n  `attributes` varchar(50) DEFAULT NULL,\n  `isOriginalTitle` smallint(6) DEFAULT NULL,\n  PRIMARY KEY (`ID`),\n  KEY `titleid_ordering` (`titleid`,`ordering`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n\n\nDROP TABLE IF EXISTS `title_basics`;\nCREATE TABLE `title_basics` (\n  `ID` bigint(20) NOT NULL AUTO_INCREMENT,\n  `tconst` varchar(20) DEFAULT NULL,\n  `titletype` varchar(15) DEFAULT NULL,\n  `primaryTitle` varchar(255) DEFAULT NULL,\n  `originalTitle` varchar(255) DEFAULT NULL,\n  `isAdult` smallint(6) DEFAULT NULL,\n  `startYear` varchar(10) DEFAULT NULL,\n  `endYear` varchar(10) DEFAULT NULL,\n  `runtimeMinutes` varchar(5) DEFAULT NULL,\n  `genres` varchar(255) DEFAULT NULL,\n  PRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n\n\nDROP TABLE IF EXISTS `title_crew`;\nCREATE TABLE `title_crew` (\n  `ID` bigint(20) NOT NULL AUTO_INCREMENT,\n  `tconst` varchar(20) DEFAULT NULL,\n  `directors` varchar(1000) DEFAULT NULL,\n  `writers` varchar(1000) DEFAULT NULL,\n  PRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n\n\nDROP TABLE IF EXISTS `title_episode`;\nCREATE TABLE `title_episode` (\n  `ID` bigint(20) NOT NULL AUTO_INCREMENT,\n  `tconst` varchar(20) DEFAULT NULL,\n  `parenttconst` varchar(20) DEFAULT NULL,\n  `seasonNumber` varchar(5) DEFAULT NULL,\n  `episodeNumber` varchar(5) DEFAULT NULL,\n  PRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n\n\nDROP TABLE IF EXISTS `title_principals`;\nCREATE TABLE `title_principals` (\n  `ID` bigint(20) NOT NULL AUTO_INCREMENT,\n  `tconst` varchar(20) DEFAULT NULL,\n  `ordering` varchar(5) DEFAULT NULL,\n  `nconst` varchar(20) DEFAULT NULL,\n  `category` varchar(50) DEFAULT NULL,\n  `job` varchar(255) DEFAULT NULL,\n  `charac` varchar(100) DEFAULT NULL,\n  PRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n\n\nDROP TABLE IF EXISTS `title_ratings`;\nCREATE TABLE `title_ratings` (\n  `ID` bigint(20) NOT NULL AUTO_INCREMENT,\n  `tconst` varchar(20) DEFAULT NULL,\n  `averageRating` decimal(5,2) DEFAULT NULL,\n  `numVotes` mediumtext,\n  PRIMARY KEY (`ID`)\n) ENGINE=InnoDB DEFAULT CHARSET=latin1;\n\n\n-- 2021-12-16 14:05:28\n\n<\/pre><\/div>\n\n\n<p><strong>SOURCE CODE<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">read-tsv.h<\/pre>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &lt;wx\/wxprec.h&gt;\n#ifndef WX_PRECOMP\n\t#include &lt;wx\/wx.h&gt;\n#endif\n#include &lt;wx\/textfile.h&gt;\n#include &lt;iostream&gt;\n#include &lt;fstream&gt;\n\nclass TSVReader {\n\n\tprivate:\n\t   wxString mPath;\n\t   wxString mTable;\n\t   wxString mFieldListSQL;\n\t   wxString getFieldList(wxString tablename);\n\t   wxString mSQLFileName;\n\t   std::ofstream mFileOut;\n\t   \n\tpublic:\n\t   TSVReader(wxString path, wxString table);\n\t   void readData();\n\t   void processLine(std::wstring, int lineCount);\n\n};\n\n\/\/ for each tsv file, define mysql table name, \n\/\/ field count and name of fields. \n\/\/ The field info ignores the ID column which is an autoincremented PK \n\/\/\nconst static wxString TABLE_TITLE_AKAS = wxT(&quot;title_akas&quot;);\nconst static int TITLE_AKAS_FIELD_COUNT = 8;\nconst static wxString TITLE_AKAS_FIELDS&#x5B;] = {wxT(&quot;titleid&quot;), wxT(&quot;ordering&quot;), wxT(&quot;title&quot;), wxT(&quot;region&quot;),\n\t\t\twxT(&quot;language&quot;), wxT(&quot;types&quot;), wxT(&quot;attributes&quot;), wxT(&quot;isOriginalTitle&quot;)};\n\n\nconst static wxString TABLE_TITLE_BASICS = wxT(&quot;title_basics&quot;);\nconst static int TITLE_BASICS_FIELD_COUNT = 9;\nconst static wxString TITLE_BASICS_FIELDS&#x5B;] = {wxT(&quot;tconst&quot;), wxT(&quot;titleType&quot;), wxT(&quot;primaryTitle&quot;), wxT(&quot;originalTitle&quot;), wxT(&quot;isAdult&quot;),\n\t\t\twxT(&quot;startYear&quot;), wxT(&quot;endYear&quot;), wxT(&quot;runtimeMinutes&quot;), wxT(&quot;genres&quot;)};\n\n\nconst static wxString TABLE_TITLE_CREW = wxT(&quot;title_crew&quot;);\nconst static int TITLE_CREW_FIELD_COUNT = 3;\nconst static wxString TITLE_CREW_FIELDS&#x5B;] = {wxT(&quot;tconst&quot;), wxT(&quot;directors&quot;), wxT(&quot;writers&quot;)};\n\nconst static wxString TABLE_TITLE_EPISODE = wxT(&quot;title_episode&quot;);\nconst static int TITLE_EPISODE_FIELD_COUNT = 4;\nconst static wxString TITLE_EPISODE_FIELDS&#x5B;] = {wxT(&quot;tconst&quot;), wxT(&quot;parenttconst&quot;), wxT(&quot;seasonNumber&quot;), wxT(&quot;episodeNumber&quot;)};\n\nconst static wxString TABLE_TITLE_PRINCIPALS = wxT(&quot;title_principals&quot;);\nconst static int TITLE_PRINCIPALS_FIELD_COUNT = 6;\nconst static wxString TITLE_PRINCIPALS_FIELDS&#x5B;] = {wxT(&quot;tconst&quot;), wxT(&quot;ordering&quot;), wxT(&quot;nconst&quot;), wxT(&quot;category&quot;), wxT(&quot;job&quot;), wxT(&quot;charac&quot;)};\n\nconst static wxString TABLE_TITLE_RATINGS = wxT(&quot;title_ratings&quot;);\nconst static int TITLE_RATINGS_FIELD_COUNT = 3;\nconst static wxString TITLE_RATINGS_FIELDS&#x5B;] = {wxT(&quot;tconst&quot;), wxT(&quot;averageRating&quot;), wxT(&quot;numVotes&quot;)};\n\nconst static wxString TABLE_NAME_BASICS = wxT(&quot;name_basics&quot;);\nconst static int NAME_BASICS_FIELD_COUNT = 6;\nconst static wxString NAME_BASICS_FIELDS&#x5B;] = {wxT(&quot;nconst&quot;), wxT(&quot;primaryName&quot;), wxT(&quot;birthYear&quot;), wxT(&quot;deathYear&quot;), wxT(&quot;primaryProfession&quot;),\n\t\t\twxT(&quot;knownForTitles&quot;)};\n\n\n\n<\/pre><\/div>\n\n\n<pre class=\"wp-block-preformatted\">read-tsv.cpp<\/pre>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &lt;codecvt&gt;\n#include &lt;sstream&gt;\n#include &lt;wx\/tokenzr.h&gt;\n#include &quot;read-tsv.h&quot;\n\n\/**\n * Ctor\n * @param path - path to tsv file\n * @param table - name of mysql table\n *\/\nTSVReader::TSVReader(wxString path, wxString table) {\n\tmPath = path;\n\tmTable = table;\n\tmFieldListSQL = getFieldList(mTable);\n\tmSQLFileName = table.append(&quot;.sql&quot;);\n\n\t\/\/delete sql file if it already exists\n\tif (wxFileExists(mSQLFileName))\n\t\twxRemoveFile(mSQLFileName);\n}\n\n\/**\n * Get the INSERT sql fragment with list of mysql field names based on the table name\n * @param tablename - name of mysql table\n * @return retVal - SQL insert statement prefix\n *\/\nwxString TSVReader::getFieldList(wxString tablename) {\n\twxString retVal = wxT(&quot;(&quot;);\n\tif (mTable == TABLE_TITLE_AKAS) {\n\t\tfor(int i = 0; i &lt; TITLE_AKAS_FIELD_COUNT; i++) {\n\t\t\tretVal.Append(wxT(&quot;`&quot;)).Append(TITLE_AKAS_FIELDS&#x5B;i]).Append(wxT(&quot;`,&quot;));\n\t\t}\n\t}\n\telse if (mTable == TABLE_TITLE_BASICS) {\n\t\tfor(int i = 0; i &lt; TITLE_BASICS_FIELD_COUNT; i++) {\n\t\t\tretVal.Append(wxT(&quot;`&quot;)).Append(TITLE_BASICS_FIELDS&#x5B;i]).Append(wxT(&quot;`,&quot;));\n\t\t}\n\t}\n\telse if (mTable == TABLE_TITLE_CREW) {\n\t\tfor(int i = 0; i &lt; TITLE_CREW_FIELD_COUNT; i++) {\n\t\t\tretVal.Append(wxT(&quot;`&quot;)).Append(TITLE_CREW_FIELDS&#x5B;i]).Append(wxT(&quot;`,&quot;));\n\t\t}\n\t}\n\telse if (mTable == TABLE_TITLE_EPISODE) {\n\t\tfor(int i = 0; i &lt; TITLE_EPISODE_FIELD_COUNT; i++) {\n\t\t\tretVal.Append(wxT(&quot;`&quot;)).Append(TITLE_EPISODE_FIELDS&#x5B;i]).Append(wxT(&quot;`,&quot;));\n\t\t}\n\t}\n\telse if (mTable == TABLE_TITLE_PRINCIPALS) {\n\t\tfor(int i = 0; i &lt; TITLE_PRINCIPALS_FIELD_COUNT; i++) {\n\t\t\tretVal.Append(wxT(&quot;`&quot;)).Append(TITLE_PRINCIPALS_FIELDS&#x5B;i]).Append(wxT(&quot;`,&quot;));\n\t\t}\n\t}\n\telse if (mTable == TABLE_TITLE_RATINGS) {\n\t\tfor(int i = 0; i &lt; TITLE_RATINGS_FIELD_COUNT; i++) {\n\t\t\tretVal.Append(wxT(&quot;`&quot;)).Append(TITLE_RATINGS_FIELDS&#x5B;i]).Append(wxT(&quot;`,&quot;));\n\t\t}\n\t}\n\telse if (mTable == TABLE_NAME_BASICS) {\n\t\tfor(int i = 0; i &lt; NAME_BASICS_FIELD_COUNT; i++) {\n\t\t\tretVal.Append(wxT(&quot;`&quot;)).Append(NAME_BASICS_FIELDS&#x5B;i]).Append(wxT(&quot;`,&quot;));\n\t\t}\n\t}\n\n\n\t\/\/ remove trailing comma\n\tif (retVal != wxT(&quot;(&quot;))\n\t\tretVal = retVal.Left(retVal.Len()-1);\n\tretVal.Append(wxT(&quot;) &quot;));\n\treturn retVal;\n}\n\n\/**\n * Read data line by line from tsv file. Each line is then processed to generate an INSERT sql statement. \n * These statements are appended to an sql file.\n *\/\nvoid TSVReader::readData() {\n\n\tstd::wifstream infile(mPath);\n\tinfile.imbue(std::locale(infile.getloc(),\n\t       new std::codecvt_utf8&lt;wchar_t, 0x10ffff&gt;));\n\tstd::wstring line;\n\n\tmFileOut.open(mSQLFileName, std::ios_base::app);\n\t\n\tlong lineCount = 0;\n\twxPuts(wxT(&quot;Reading &quot;) + mPath);\n\tbool isTitleRow = true; \/\/ first row is column titles\n\n\twhile (getline(infile, line)) {\n\t\tif (isTitleRow) {\n\t\t\tisTitleRow = false;\n\t\t\tcontinue;\n\t\t}\n\t\tprocessLine(line, lineCount);\n\t\tlineCount++;\n\n\t}\n\tmFileOut.close();\n\twxPuts(wxString::Format(wxT(&quot;%ld lines&quot;), lineCount));\n}\n\n\/**\n * Convert each line in tsv file to an INSERT sql statement\n * @param line - tsv line \n * @param lineCount - counter of lines read from tsv file\n *\/\nvoid TSVReader::processLine(std::wstring line, int lineCount) {\n\twxString sql = wxT(&quot;insert into &quot;);\n\tsql.Append(mTable).Append(mFieldListSQL).Append(wxT(&quot;values (&quot;));\n\twxString token = wxT(&quot;&quot;);\n\twxStringTokenizer tokenizer(line, &quot;\\t&quot;);\n\twhile (tokenizer.HasMoreTokens()) {\n\t\ttoken = tokenizer.GetNextToken();\n\t\ttoken.Replace(wxT(&quot;&#039;&quot;), wxT(&quot;\\\\;&quot;));\n\t\tsql.Append(&quot;&#039;&quot;).Append(token).Append(&quot;&#039;,&quot;);\n\t}\n\t\/\/ remove trailing comma\n\tif (token != wxT(&quot;&quot;))\n\t     sql = sql.Left(sql.Len()-1);\n\tsql.Append(wxT(&quot;);&quot;));\n\tmFileOut &lt;&lt; sql &lt;&lt; std::endl;\n\n}\n\n<\/pre><\/div>\n\n\n<pre class=\"wp-block-preformatted\">main.cpp<\/pre>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\n#include &quot;read-tsv.h&quot;\n\n\/\/\/\n\/\/ First arg is the tsv filename, Second arg is the mysql table name\n\/\/\/\nint main(int argc, char **argv) {\n\twxInitialize();\n\twxString filename = wxT(&quot;&quot;);\n\twxString table = wxT(&quot;&quot;);\n\tif (argc &gt; 2) {\n\t\tfilename = argv&#x5B;1];\n\t\ttable = argv&#x5B;2];\n\t} else {\n\t   wxPuts(&quot;No tsv file and\/or tablename specified&quot;);\n\t   return -1;\n\t}\n\twxPuts(&quot;Reading file..&quot; + filename);\n\tTSVReader tsv(filename, table);\n\ttsv.readData();\n\twxPuts(&quot;Closed file&quot;);\n\twxUninitialize();\n}\n<\/pre><\/div>\n\n\n<p>To build the source under Windows change the sample makefile as provided in the Windows setup of wxWidgets blog post. For Ubuntu use <\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">g++ main.cpp read-tsv.cpp <code>``wx-config --cxxflags --libs<\/code>`` -o read-tsv\n<\/pre>\n\n\n\n<p>Use single backticks in the above command and not double backticks as shown above<\/p>\n\n\n\n<p><strong>EXECUTION<\/strong><\/p>\n\n\n\n<p>For each tsv file, run the command<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">.\/read-tsv &lt;tsv filename&gt; &lt;table name&gt;<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">Eg. .\/read-tsv name.basics.tsv name_basics<\/pre>\n\n\n\n<p>Once you have run this for all the tsv files, you will end up with corresponding sql files for each table. Process each of these sql files in mysql . You can do either by indirection at the command prompt:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">mysql --user=username --password=mypassword imdb_db &lt; name_basics.sql<\/pre>\n\n\n\n<p>Or you can do it using the <em>source<\/em> command:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">mysql --user=username --password=mypassword \n&gt; use imdb_db;\n&gt; source 'name_basics.sql';\n<\/pre>\n\n\n\n<p>Note that if you run the sql file twice for some reason, be sure to truncate the table first, otherwise it will insert duplicate data.<\/p>\n\n\n\n<p>The table screenshots with the imported data are shown below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"490\" src=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/name-basics-940x490.png\" alt=\"\" class=\"wp-image-3859\" srcset=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/name-basics-940x490.png 940w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/name-basics-620x324.png 620w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/name-basics-300x157.png 300w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/name-basics-768x401.png 768w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/name-basics.png 987w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"887\" height=\"415\" src=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-akas.png\" alt=\"\" class=\"wp-image-3860\" srcset=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-akas.png 887w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-akas-620x290.png 620w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-akas-300x140.png 300w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-akas-768x359.png 768w\" sizes=\"auto, (max-width: 887px) 100vw, 887px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"280\" src=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-basics-940x280.png\" alt=\"\" class=\"wp-image-3861\" srcset=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-basics-940x280.png 940w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-basics-620x185.png 620w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-basics-300x89.png 300w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-basics-768x229.png 768w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-basics.png 1344w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"431\" height=\"424\" src=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-crew.png\" alt=\"\" class=\"wp-image-3862\" srcset=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-crew.png 431w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-crew-300x295.png 300w\" sizes=\"auto, (max-width: 431px) 100vw, 431px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"498\" height=\"423\" src=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-episode.png\" alt=\"\" class=\"wp-image-3863\" srcset=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-episode.png 498w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-episode-300x255.png 300w\" sizes=\"auto, (max-width: 498px) 100vw, 498px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"378\" height=\"418\" src=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-ratings.png\" alt=\"\" class=\"wp-image-3864\" srcset=\"https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-ratings.png 378w, https:\/\/truelogic.org\/wordpress\/wp-content\/uploads\/2021\/12\/title-ratings-300x332.png 300w\" sizes=\"auto, (max-width: 378px) 100vw, 378px\" \/><\/figure>\n\n\n\n<p><strong>NEXT STEPS<\/strong><\/p>\n\n\n\n<p>In the next blog post, we will look into optimizing the database and cleaning it up a bit.<\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>OVERVIEW IMDB , being the world&#8217;s best known and largest movie and TV website, does not provide any API to use their data. However , <a class=\"mh-excerpt-more\" href=\"https:\/\/truelogic.org\/wordpress\/2021\/12\/16\/convert-imdb-data-to-mysql-tables-using-c-part-1\/\" title=\"Convert IMDB data to MySql tables using C++ &#8211; Part 1\">[&#8230;]<\/a><\/p>\n<\/div>","protected":false},"author":1,"featured_media":3849,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[302],"tags":[],"class_list":["post-3848","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cc"],"_links":{"self":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/3848","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/comments?post=3848"}],"version-history":[{"count":14,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/3848\/revisions"}],"predecessor-version":[{"id":3869,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/posts\/3848\/revisions\/3869"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/media\/3849"}],"wp:attachment":[{"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/media?parent=3848"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/categories?post=3848"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/truelogic.org\/wordpress\/wp-json\/wp\/v2\/tags?post=3848"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}