{"id":46756,"date":"2023-04-01T00:00:00","date_gmt":"2023-04-01T07:00:00","guid":{"rendered":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/"},"modified":"2025-11-13T12:56:32","modified_gmt":"2025-11-13T20:56:32","slug":"visualize-global-population-data-with-mapbox-node-js-and-griddb","status":"publish","type":"post","link":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/","title":{"rendered":"Visualize Global Population Data with Mapbox, Node.js, and GridDB"},"content":{"rendered":"<h2>What We Will Build?<\/h2>\n<p>This post will show you how to create a web-based map displaying world population data. The data is extracted from <a href=\"https:\/\/www.worldometers.info\/\">worldometers<\/a> and using React, Mapbox GL JS, Node.js, and GridDB to build the whole web-based map application. The world map will display the top 10 countries with the most population data.<\/p>\n<h2>Run the Project<\/h2>\n<p>To launch the project, visit the project&#8217;s <a href=\"https:\/\/github.com\/junwatu\/griddb-codes\">repository<\/a>. Clone the repository, ensure that you have Node.js version 18, install all required dependencies, and start the project.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">git clone git@github.com:junwatu\/griddb-codes.git\n\ncd griddb-codes\n\ncore enable\n\ncorepack prepare pnpm@7.30.0 --activate\n\npnpm install\n\ncd packages\/data-server\/\n\npnpm install\n\ncd ..\/client\n\npnpm install\n\ncd ..\/..\/\n\nnpm start<\/code><\/pre>\n<\/div>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/run-world-population-project.gif\"><img fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/run-world-population-project.gif\" alt=\"\" width=\"1280\" height=\"720\" class=\"aligncenter size-full wp-image-29519\" \/><\/a><\/p>\n<p>Go to http:\/\/localhost:5173 in the browser to open the web map.<\/p>\n<h2>The Development Flow<\/h2>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/project-diagram.svg\"><img decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/project-diagram.svg\" alt=\"\" width=\"1681\" height=\"1031\" class=\"aligncenter size-full wp-image-29518\" \/><\/a><\/p>\n<p>The development flow for this project can be breakdown into a few steps:<\/p>\n<h2>Data Acquisition<\/h2>\n<p>First, we need to get real-time data from <a href=\"https:\/\/www.worldometers.info\/\">worldometers<\/a>. We can get the data by scrapping the website or using API and then getting the needed data.<\/p>\n<p>The data will be extracted at regular intervals and then stored in the GridDB database. The data stored can be used for further analysis, prediction, reporting, etc.<\/p>\n<h2>Back-end Development<\/h2>\n<p>We will use Node.js to code the server-side application server.<\/p>\n<p><em>Why Node.js?<\/em><\/p>\n<blockquote>\n<p>JavaScript is the lingua franca for full-stack application development, so it&#8217;s the obvious choice.<\/p>\n<\/blockquote>\n<p>The application server we make is WebSocket-based, and Node.js will interact with GridDB for data storage, handle retrieval data from worldometers, and handle requests and responses from the client UI.<\/p>\n<h2>Front-end Development<\/h2>\n<p>We use React.js to create the user interface and to display the world population data visually, we&#8217;ll use Mapbox GL JS, a powerful mapping library. This library enables the creation of interactive, customizable maps. We&#8217;ll integrate Mapbox GL JS with our React application to render a world map with labels representing the population data.<\/p>\n<h2>Prerequisite<\/h2>\n<p>Before we code the application, we need to set up the software and tools for development. We use Ubuntu 20.04 on WSL 2 on Windows 11 OS.<\/p>\n<blockquote>\n<p>WSL is only available on Windows 10 version 2004 and higher (Build 19041 and higher). Go ahead to this <a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/wsl\/install\">link<\/a> for a new WSL installation.<\/p>\n<\/blockquote>\n<h2>GridDB<\/h2>\n<p><a href=\"https:\/\/griddb.net\/en\/\">GridDB<\/a>\u2122 is a highly scalable, in-memory NoSQL time-series database optimized for IoT and Big Data. What&#8217;s important to note is it has two types of container categories:<\/p>\n<h3>Collection Containers<\/h3>\n<p>This type of container is similar to a traditional relational database. The data is stored as key values, and the collection container support basic CRUD (Create, Read, Update, and Delete) operation.<\/p>\n<h3>TimeSeries Containers<\/h3>\n<p>This container is designed explicitly for managing time-series data, a sequence of data points indexed by time. Each record in a TimeSeries container has a timestamp, which serves as its unique key, and the data in this container is &#8220;append only&#8221; except upon deletion if requested.<\/p>\n<h3>Installation<\/h3>\n<p>To install GridDB on WSL there are a few things that we should know.<\/p>\n<p>\u26a0\ufe0f GridDB deb package uses <code>systemd<\/code>, but Ubuntu 20.04 on WSL 2 Windows 11 uses <code>SysVinit<\/code>, so you need to enable <code>systemd<\/code> on Ubuntu WSL by editing the file <code>\/etc\/wsl.conf<\/code> (create it if this file doesn&#8217;t exist)<\/p>\n<p>Inside your Ubuntu instance, add the following modification to <code>\/etc\/wsl.conf<\/code><sup id=\"fnref:1\"><a href=\"#fn:1\" rel=\"footnote\">1<\/a><\/sup><\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">[boot]\nsystemd=true<\/code><\/pre>\n<\/div>\n<p>Open the Windows terminal to restart wsl with the following command.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">wsl --shutdown<\/code><\/pre>\n<\/div>\n<p>Then start wsl again with the command.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">wsl<\/code><\/pre>\n<\/div>\n<p>To install GridDB, follow the installation instruction on <a href=\"https:\/\/docs.griddb.net\/latest\/gettingstarted\/using-apt\/#install-with-apt-get\">https:\/\/docs.griddb.net\/latest\/gettingstarted\/using-apt\/#install-with-apt-get<\/a>.<\/p>\n<p>Run GridDB and check if the service is running. Use this command<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">sudo systemctl status gridstore<\/code><\/pre>\n<\/div>\n<p>And if everything ok you will get a message like this.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">\u25cf gridstore.service - GridDB database server.\n     Loaded: loaded (\/lib\/systemd\/system\/gridstore.service; enabled; vendor preset: enabled)\n     Active: active (running) since Thu 2023-03-16 18:56:13 +07; 58min ago\n    Process: 314 ExecStart=\/usr\/griddb\/bin\/gridstore start (code=exited, status=0\/SUCCESS)\n   Main PID: 393 (gsserver)\n      Tasks: 34 (limit: 4605)\n     Memory: 138.5M\n        CPU: 20.129s\n     CGroup: \/system.slice\/gridstore.service\n             \u2514\u2500393 \/usr\/bin\/gsserver --conf \/var\/lib\/gridstore\/conf\n\nMar 16 18:56:10 GenAI systemd[1]: Starting GridDB database server....\nMar 16 18:56:10 GenAI gridstore[314]: Starting gridstore service:\nMar 16 18:56:13 GenAI gridstore[392]: ..\nMar 16 18:56:13 GenAI gridstore[392]: Started node.\nMar 16 18:56:13 GenAI gridstore[314]: [ OK ]\nMar 16 18:56:13 GenAI systemd[1]: Started GridDB database server..<\/code><\/pre>\n<\/div>\n<p>No need to start GridDB manually because on every OS reboot, this service will go up.<\/p>\n<h2>Node.js<\/h2>\n<p>To install<sup id=\"fnref:2\"><a href=\"#fn:2\" rel=\"footnote\">2<\/a><\/sup> Node.js LTS, follow the commands below<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">curl -fsSL https:\/\/deb.nodesource.com\/setup_18.x | sudo -E bash - &&\nsudo apt-get install -y nodejs<\/code><\/pre>\n<\/div>\n<p>We will be using <a href=\"https:\/\/github.com\/griddb\/node-api\">griddb node-api<\/a> to connect our application with GridDB, but before that, we should install the <a href=\"https:\/\/github.com\/griddb\/c_client\">griddb c client<\/a>. The GridDB C Client provides a C interface for GridDB.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">wget https:\/\/github.com\/griddb\/c_client\/releases\/download\/v5.0.0\/griddb-c-client_5.0.0_amd64.deb\nsudo dpkg -i griddb-c-client_5.0.0_amd64.deb<\/code><\/pre>\n<\/div>\n<h3>GridDB node-api<\/h3>\n<p>To connect to GridDB from Node.js, we should use <code>griddb-node-api<\/code>. This package is built using node-addon-api, and there are two ways to use it:<\/p>\n<p>1&#46; Compile from the source code. This way is the right way if you need to use griddb-node-api on a specific node.js version.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">git clone git@github.com:griddb\/node-api.git\ncd node-api\nnpm install<\/code><\/pre>\n<\/div>\n<p>If there is an error message like this<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">gyp ERR! stack Error: not found: make<\/code><\/pre>\n<\/div>\n<p>That means you should install the <code>build-essentials<\/code> package in Ubuntu, and if everything success you will get a file, <code>griddb.node<\/code>, and then you need to include it in <code>NODE_PATH<\/code><\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">export NODE_PATH=$(pwd)<\/code><\/pre>\n<\/div>\n<p>2&#46; Install the npm package <code>griddb-node-api<\/code> directly into our project.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">npm install griddb-node-api<\/code><\/pre>\n<\/div>\n<p>We will use the second way for our project because it&#8217;s simpler, and we use Node 18 LTS.<\/p>\n<h2>VSCode<\/h2>\n<p>As stated earlier, we use OS Ubuntu 20.04 on WSL Windows 11. To code from Windows, we use Visual Studio Code because it has a remarkable <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=ms-vscode-remote.remote-wsl\">remote WSL plugin<\/a><\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/vscode-remote.png\"><img decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/vscode-remote.png\" alt=\"\" width=\"1920\" height=\"1080\" class=\"aligncenter size-full wp-image-29512\" srcset=\"\/wp-content\/uploads\/2023\/03\/vscode-remote.png 1920w, \/wp-content\/uploads\/2023\/03\/vscode-remote-300x169.png 300w, \/wp-content\/uploads\/2023\/03\/vscode-remote-1024x576.png 1024w, \/wp-content\/uploads\/2023\/03\/vscode-remote-768x432.png 768w, \/wp-content\/uploads\/2023\/03\/vscode-remote-1536x864.png 1536w, \/wp-content\/uploads\/2023\/03\/vscode-remote-150x85.png 150w, \/wp-content\/uploads\/2023\/03\/vscode-remote-600x338.png 600w\" sizes=\"(max-width: 1920px) 100vw, 1920px\" \/><\/a><\/p>\n<p>Ok. That&#8217;s a long setup before we code the application itself, but it&#8217;s necessary so our development environment is transparent.<\/p>\n<h2>Project Structure Directory<\/h2>\n<p>We use <code>pnpm<\/code> instead of npm because <code>pnpm<\/code> is storage efficient and supports workspaces. We will create a monorepo that holds server and client codes.<\/p>\n<p>To activate <code>pnpm<\/code> use <code>corepack<\/code> from Node.js<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">corepack prepare pnpm@7.30.0 --activate<\/code><\/pre>\n<\/div>\n<p><em>Why monorepo?<\/em><\/p>\n<blockquote>\n<p>Because it&#8217;s good for future development, if you want to add another collaborator, everyone will be working on the same code base.<\/p>\n<\/blockquote>\n<p>Start the project by creating a directory for the monorepo<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">mkdir world-population\ncd world-population\npnpm init<\/code><\/pre>\n<\/div>\n<p>Then create <code>packages<\/code> directory that will hold our project codes. Server code in <code>data-server<\/code> directory and client code in <code>client<\/code> directory.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">mkdir packages\nmkdir packages\/data-server\nmkdir packages\/client<\/code><\/pre>\n<\/div>\n<p><code>pnpm<\/code> handling project workspaces by reading the config from <code>pnpm-workspaces.yaml<\/code>, so you need to create it and fill with the content below.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\"># pnpm-workspaces.yaml\npackages:\n  # all packages in direct subdirs of packages\/\n  - \"packages\/*<\/code><\/pre>\n<\/div>\n<p>This tree structure might be typical of a Node.js project that has separate client and server codebases. Organized as packages within a monorepo and managed with the <code>pnpm<\/code> package manager.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">.\n\u251c\u2500\u2500 .gitignore\n\u251c\u2500\u2500 package.json\n\u251c\u2500\u2500 packages\n\u2502   \u251c\u2500\u2500 data-server\n\u2502   \u2514\u2500\u2500 client\n\u2514\u2500\u2500 pnpm-workspaces.yaml<\/code><\/pre>\n<\/div>\n<h2>Let&#8217;s Code<\/h2>\n<p>The first thing to do is initialize the server project and install the main npm packages.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">cd packages\/data-server\npnpm init\ncd ..\/..\/\npnpm --filter data-server install griddb-node-api express ws puppeteer<\/code><\/pre>\n<\/div>\n<h3>Data Extraction<\/h3>\n<p>This project uses data from Worldometers.<\/p>\n<blockquote>\n<p>Worldometers is a website that provides real-time statistics on various topics, including world population, government and economics, society and media, the environment, food, water, energy, and health.<\/p>\n<\/blockquote>\n<p>To get data from a website there are a few ways we can use:<\/p>\n<ol>\n<li>Using API<\/li>\n<li>Scraping<\/li>\n<\/ol>\n<p>Unfortunately, Worldometers does not provide API, so our last option is to scrap the website.<\/p>\n<p>One thing to note is Worldometers have dynamic data, meaning they provide real-time data. You cannot use JavaScript libraries such as Cheerio for data extraction. The best choice is to use Puppeteer to get such dynamic content.<\/p>\n<blockquote>\n<p>Puppeteer can be more resource-intensive as it launches a headless browser instance to render web pages. However, it offers more capabilities, such as handling dynamic content and user interactions.<\/p>\n<\/blockquote>\n<p>Two endpoint URLs will provide us with the data. One is for the total world population, and the second is for the total world population by country.<\/p>\n<ul>\n<li>https:\/\/www.worldometers.info\/world-population\/<\/li>\n<li>https:\/\/www.worldometers.info\/world-population\/population-by-country\/<\/li>\n<\/ul>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">const worldPopDataSource = \"https:\/\/www.worldometers.info\/world-population\/\";\n\/**\n * fetch world population data\n *\/\nconst fetchWorldPopulationData = async () => {\n  const browser = await puppeteer.launch();\n  const page = await browser.newPage();\n\n  await page.goto(worldPopDataSource);\n\n  const extractData = async () => {\n    \/\/ Extract data from the page\n    const data = await page.evaluate(() => {\n      const populationElement = document.querySelector(\".rts-counter\");\n      const population = populationElement.textContent.replace(\/[ns]+\/g, \"\");\n      return { population };\n    });\n\n    return data;\n  };\n\n  const popData = await extractData();\n  await browser.close();\n\n  return popData;\n};<\/code><\/pre>\n<\/div>\n<p>The data returned by <code>fetchWorldPopulationData<\/code> function is simply a JavaScript object.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">{\n  type: 'worldPopulationData',\n  worldPopulation: {\n    population: '8,022,758,957',\n    timestamp: 1679222700112\n  }\n}<\/code><\/pre>\n<\/div>\n<p>The code for data extraction of world population by country is in the repository project.<\/p>\n<p>The output will be an array, with keys: <code>country<\/code> name, country <code>coordinate<\/code> and the <code>population<\/code>.<\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/world-pop-by-country.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/world-pop-by-country.png\" alt=\"\" width=\"1088\" height=\"612\" class=\"aligncenter size-full wp-image-29514\" srcset=\"\/wp-content\/uploads\/2023\/03\/world-pop-by-country.png 1088w, \/wp-content\/uploads\/2023\/03\/world-pop-by-country-300x169.png 300w, \/wp-content\/uploads\/2023\/03\/world-pop-by-country-1024x576.png 1024w, \/wp-content\/uploads\/2023\/03\/world-pop-by-country-768x432.png 768w, \/wp-content\/uploads\/2023\/03\/world-pop-by-country-150x85.png 150w, \/wp-content\/uploads\/2023\/03\/world-pop-by-country-600x338.png 600w\" sizes=\"(max-width: 1088px) 100vw, 1088px\" \/><\/a><\/p>\n<h2>Data Store<\/h2>\n<p>We will use time-series containers for storing world population data. As with any other database, we need to connect to it first. On GridDB, we need to connect to the cluster.<\/p>\n<p>You can see the cluster configuration at<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">\/var\/lib\/gridstore\/conf\/gs_cluster.json<\/code><\/pre>\n<\/div>\n<p>And make sure that the port we put in the code is the value of the transaction key because there are a few ports there.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">const initStore = async () => {\n  const factory = griddb.StoreFactory.getInstance();\n  try {\n    \/\/ Connect to GridDB Cluster\n    const store = await factory.getStore({\n      host: \"127.0.0.1\",\n      port: 10001,\n      clusterName: \"myCluster\",\n      username: \"admin\",\n      password: \"admin\",\n    });\n    return store;\n  } catch (e) {\n    throw e;\n  }\n};<\/code><\/pre>\n<\/div>\n<p>After that, we need to create a container to store our data. The <code>initContainer()<\/code> function provides information about the container&#8217;s schema, including the names and data types of its columns.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">function initContainer() {\n  const conInfo = new griddb.ContainerInfo({\n    name: containerName,\n    columnInfoList: [\n      [\"timestamp\", griddb.Type.TIMESTAMP],\n      [\"value\", griddb.Type.DOUBLE],\n    ],\n    type: griddb.ContainerType.TIME_SERIES,\n  });\n\n  return conInfo;\n}<\/code><\/pre>\n<\/div>\n<p>Please note that the <code>initContainer()<\/code> function will not create a container. To create a container, GridDB API provide us with <code>putContainer()<\/code> function.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">async function createContainer(store, conInfo) {\n  try {\n    const timeSeriesDB = await store.putContainer(conInfo);\n    return timeSeriesDB;\n  } catch (err) {\n    console.error(err);\n    throw err;\n  }\n}<\/code><\/pre>\n<\/div>\n<h3>How to Store the Data<\/h3>\n<p>Store the data is pretty easy. First, get the container connection, then use <code>put()<\/code> to save the data into the GridDB container.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">db.put(data);<\/code><\/pre>\n<\/div>\n<p><code>db<\/code> is the connection reference that is returned by <code>createConnection()<\/code> function.<\/p>\n<p>The important thing to note for this project is the data should be stored periodically. The simplest way to do this is by using JavaScript native function, <code>setInterval()<\/code>.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">function updateClientsWithWorldPopulationDataPeriodically(clients) {\n  updateClientsWithWorldPopulationData(clients);\n  setTimeout(\n    () => updateClientsWithWorldPopulationDataPeriodically(clients),\n    worldDataUpdateTime\n  );\n}\n\n\/\/ Call the function to start the periodic updates\nupdateClientsWithWorldPopulationDataPeriodically(wss.clients);<\/code><\/pre>\n<\/div>\n<p>The default time to extract data is set by variable <code>worldDataUpdateTime<\/code> which is 5 second. Means that, every 5 second we update the data.<\/p>\n<h2>Read Data from GridDB<\/h2>\n<p>GridDB supports SQL, so you can use raw SQL to retrieve the data. By using <code>query()<\/code> and <code>fetch()<\/code> we can easily get the data based on a SQL query.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">async function queryAll(db) {\n  const query = db.query(\n    `SELECT * FROM ${containerName} ORDER BY timestamp DESC LIMIT 1`\n  );\n\n  try {\n    const rowset = await query.fetch();\n    const results = [];\n\n    while (rowset.hasNext()) {\n      const row = rowset.next();\n      const rowData = { timestamp: `${row[0]}`, population: row[1] };\n      results.push(rowData);\n    }\n\n    return results;\n  } catch (err) {\n    console.log(err);\n    throw err;\n  }\n}<\/code><\/pre>\n<\/div>\n<p>For the projet purposes, it need to display the latest data with the latest time stamp. We can use SQL queries to achieve this.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">sql\nSELECT * FROM [containerName] ORDER BY timestamp DESC LIMIT 1<\/code><\/pre>\n<\/div>\n<h2>Deliver Data to the Web Client<\/h2>\n<p>We use WebSocket to deliver data to the project web client, built with React and Mapbox.<\/p>\n<p><em>Why WebSocket?<\/em><\/p>\n<blockquote>\n<p>WebSocket is the optimal choice for applications requiring intensive data usage because it enables real-time, bidirectional communication between the client and server. WebSocket allows for efficient data transfer and minimizes latency, which is essential in data-intensive applications where continuous updates and rapid responsiveness are crucial.<\/p>\n<\/blockquote>\n<p>This snippet code shows us how the world population data is saved to and queried from GridDB and then sent it to the web client via WebSocket <code>ws<\/code>.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">const worldPopData = [worldPopulation.timestamp, worldPopulation.population];\nawait GridDB.insert(worldPopData, timeSeriesDb);\n\nconst result = await GridDB.queryAll(timeSeriesDb);\n\nconst jsonArray = result.map((item) => {\n  return {\n    timestamp: item.timestamp.toString(),\n    population: item.population,\n  };\n});\n\n\/\/ client is WebSocket client\nclients.forEach((client) => {\n  if (client.readyState === WebSocket.OPEN) {\n    try {\n      client.send(JSON.stringify(jsonArray));\n    } catch (error) {\n      console.error(\"Error sending data to client:\", error);\n    }\n  }\n});<\/code><\/pre>\n<\/div>\n<p>In this project, we use <a href=\"https:\/\/github.com\/websockets\/ws\">ws<\/a> for WebSocket and <a href=\"http:\/\/expressjs.com\/\">express.js<\/a> for HTTP server.<\/p>\n<h2>Web Client React + Mapbox GL JS<\/h2>\n<p>There are so many tools today for creating React-based applications. <a href=\"https:\/\/vitejs.dev\/\">Vite<\/a> is a next-generation front-end tool. It offers enhanced speed, supports ESM, and React. Making it a standout choice.<\/p>\n<p>To create a new frontend project using Vite.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">pnpm create vite\ncd client\npnpm install<\/code><\/pre>\n<\/div>\n<p>The command will ask you a few questions and make sure to choose JavaScript and React. The source code for web client is live inside the folder <code>packages\/client<\/code>.<\/p>\n<p>The client side project structure.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">.\n\u251c\u2500\u2500 index.html\n\u251c\u2500\u2500 node_modules\n\u251c\u2500\u2500 package.json\n\u251c\u2500\u2500 pnpm-lock.yaml\n\u251c\u2500\u2500 public\n\u2502   \u2514\u2500\u2500 vite.svg\n\u251c\u2500\u2500 src\n\u2502   \u251c\u2500\u2500 App.css\n\u2502   \u251c\u2500\u2500 App.jsx\n\u2502   \u251c\u2500\u2500 assets\n\u2502   \u2502   \u2514\u2500\u2500 react.svg\n\u2502   \u251c\u2500\u2500 index.css\n\u2502   \u2514\u2500\u2500 main.jsx\n\u2514\u2500\u2500 vite.config.js<\/code><\/pre>\n<\/div>\n<p>There is not much to change in the files or directories created by Vite, except <code>App.jsx<\/code> and <code>index.css<\/code> files.<\/p>\n<p><code>App.jsx<\/code> is where we code our react component and UI for Mapbox. There are only two components. One is <code>sidebar<\/code> to show the total world population, and the second is <code>map-container<\/code> to display the world map and label each country&#8217;s total population.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">&lt;div className=\"App\"&gt;\n  &lt;div className=\"sidebar\"&gt;World Population: {worldPopulation}&lt;\/div&gt;\n  &lt;div ref=\"{mapContainer}\" className=\"map-container\" \/&gt;\n&lt;\/div&gt;<\/code><\/pre>\n<\/div>\n<h3>Mapbox GL JS<\/h3>\n<p><a href=\"https:\/\/www.mapbox.com\/mapbox-gljs\">Mapbox GL JS<\/a> is a JavaScript library for vector maps on the web. Its performance, real-time styling, and interactivity features set the bar for anyone building fast and immersive web maps.<\/p>\n<p>Add Mapbox GL JS to our client-side application.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">pnpm install mapbox-gl<\/code><\/pre>\n<\/div>\n<p>Since modern browsers already support WebSocket natively, we don&#8217;t need an additional package to connect to our WebSocket server.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">const ws = new WebSocket(\"ws:\/\/localhost:3000\");\nsetSocket(ws);<\/code><\/pre>\n<\/div>\n<p>And to get the world population data, just listen to <code>message<\/code> event<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">ws.addEventListener(\"message\", (event) => {\n  const data = JSON.parse(event.data);\n\n  if (data[0].country) {\n    console.log(\"country\", data);\n    updateLabels(data);\n  } else {\n    setWorldPopulation(data[0].population);\n  }\n});<\/code><\/pre>\n<\/div>\n<p><code>updateLabels(data)<\/code> function will update every country&#8217;s label in the top 10 world population.<\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/country-map-label.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/country-map-label.png\" alt=\"\" width=\"760\" height=\"428\" class=\"aligncenter size-full wp-image-29516\" srcset=\"\/wp-content\/uploads\/2023\/03\/country-map-label.png 760w, \/wp-content\/uploads\/2023\/03\/country-map-label-300x169.png 300w, \/wp-content\/uploads\/2023\/03\/country-map-label-150x85.png 150w, \/wp-content\/uploads\/2023\/03\/country-map-label-600x338.png 600w\" sizes=\"(max-width: 760px) 100vw, 760px\" \/><\/a><\/p>\n<h3>React<\/h3>\n<p>With React, we can build components easily. For this project, we use it for creating a sidebar.<\/p>\n<p><a href=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/sidebar.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/sidebar.png\" alt=\"\" width=\"667\" height=\"71\" class=\"aligncenter size-full wp-image-29520\" srcset=\"\/wp-content\/uploads\/2023\/03\/sidebar.png 667w, \/wp-content\/uploads\/2023\/03\/sidebar-300x32.png 300w, \/wp-content\/uploads\/2023\/03\/sidebar-600x64.png 600w\" sizes=\"(max-width: 667px) 100vw, 667px\" \/><\/a><\/p>\n<p>This UI shows the total world population. Using React <code>useState<\/code>, every data update from WebSocket will trigger and render new data on the sidebar.<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-javascript\">const [worldPopulation, setWorldPopulation] = useState(0);\n\n\/\/...\/\/\n\nws.addEventListener(\"message\", (event) => {\n  const data = JSON.parse(event.data);\n\n  if (data[0].country) {\n    console.log(\"country\", data);\n    updateLabels(data);\n  } else {\n    setWorldPopulation(data[0].population);\n  }\n});<\/code><\/pre>\n<\/div>\n<p>Conceptually, this project appears straightforward. However, the implementation of a web application to visualize global population data using Mapbox, Node.js, and GridDB with real-time live data integration and live UI updates presents a more complex challenge. The real-world nature of the data and the dynamic aspects of the application add multiple layers of complexity, making it a non-trivial task to execute effectively.<\/p>\n<div class=\"footnotes\">\n<hr \/>\n<ol>\n<li id=\"fn:1\">\n<p>https:\/\/ubuntu.com\/blog\/ubuntu-wsl-enable-systemd&#160;<a href=\"#fnref:1\" rev=\"footnote\">&#8617;<\/a><\/p>\n<\/li>\n<li id=\"fn:2\">\n<p>https:\/\/github.com\/nodesource\/distribution&#160;<a href=\"#fnref:2\" rev=\"footnote\">&#8617;<\/a><\/p>\n<\/li>\n<\/ol>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>What We Will Build? This post will show you how to create a web-based map displaying world population data. The data is extracted from worldometers and using React, Mapbox GL JS, Node.js, and GridDB to build the whole web-based map application. The world map will display the top 10 countries with the most population data. [&hellip;]<\/p>\n","protected":false},"author":41,"featured_media":29513,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[121],"tags":[],"class_list":["post-46756","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Visualize Global Population Data with Mapbox, Node.js, and GridDB | GridDB: Open Source Time Series Database for IoT<\/title>\n<meta name=\"description\" content=\"What We Will Build? This post will show you how to create a web-based map displaying world population data. The data is extracted from worldometers and\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Visualize Global Population Data with Mapbox, Node.js, and GridDB | GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"og:description\" content=\"What We Will Build? This post will show you how to create a web-based map displaying world population data. The data is extracted from worldometers and\" \/>\n<meta property=\"og:url\" content=\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/\" \/>\n<meta property=\"og:site_name\" content=\"GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/griddbcommunity\/\" \/>\n<meta property=\"article:published_time\" content=\"2023-04-01T07:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-13T20:56:32+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/world-map.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"974\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"griddb-admin\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:site\" content=\"@GridDBCommunity\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"griddb-admin\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/\"},\"author\":{\"name\":\"griddb-admin\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\"},\"headline\":\"Visualize Global Population Data with Mapbox, Node.js, and GridDB\",\"datePublished\":\"2023-04-01T07:00:00+00:00\",\"dateModified\":\"2025-11-13T20:56:32+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/\"},\"wordCount\":1842,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/griddb.net\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2023\/03\/world-map.png\",\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/\",\"url\":\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/\",\"name\":\"Visualize Global Population Data with Mapbox, Node.js, and GridDB | GridDB: Open Source Time Series Database for IoT\",\"isPartOf\":{\"@id\":\"https:\/\/griddb.net\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2023\/03\/world-map.png\",\"datePublished\":\"2023-04-01T07:00:00+00:00\",\"dateModified\":\"2025-11-13T20:56:32+00:00\",\"description\":\"What We Will Build? This post will show you how to create a web-based map displaying world population data. The data is extracted from worldometers and\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#primaryimage\",\"url\":\"\/wp-content\/uploads\/2023\/03\/world-map.png\",\"contentUrl\":\"\/wp-content\/uploads\/2023\/03\/world-map.png\",\"width\":1920,\"height\":974},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/griddb.net\/en\/#website\",\"url\":\"https:\/\/griddb.net\/en\/\",\"name\":\"GridDB: Open Source Time Series Database for IoT\",\"description\":\"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL\",\"publisher\":{\"@id\":\"https:\/\/griddb.net\/en\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/griddb.net\/en\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/griddb.net\/en\/#organization\",\"name\":\"Fixstars\",\"url\":\"https:\/\/griddb.net\/en\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"contentUrl\":\"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png\",\"width\":200,\"height\":83,\"caption\":\"Fixstars\"},\"image\":{\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/griddbcommunity\/\",\"https:\/\/x.com\/GridDBCommunity\",\"https:\/\/www.linkedin.com\/company\/griddb-by-toshiba\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\",\"name\":\"griddb-admin\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g\",\"caption\":\"griddb-admin\"},\"url\":\"https:\/\/griddb.net\/en\/author\/griddb-admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Visualize Global Population Data with Mapbox, Node.js, and GridDB | GridDB: Open Source Time Series Database for IoT","description":"What We Will Build? This post will show you how to create a web-based map displaying world population data. The data is extracted from worldometers and","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/","og_locale":"en_US","og_type":"article","og_title":"Visualize Global Population Data with Mapbox, Node.js, and GridDB | GridDB: Open Source Time Series Database for IoT","og_description":"What We Will Build? This post will show you how to create a web-based map displaying world population data. The data is extracted from worldometers and","og_url":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/","og_site_name":"GridDB: Open Source Time Series Database for IoT","article_publisher":"https:\/\/www.facebook.com\/griddbcommunity\/","article_published_time":"2023-04-01T07:00:00+00:00","article_modified_time":"2025-11-13T20:56:32+00:00","og_image":[{"width":1920,"height":974,"url":"https:\/\/griddb.net\/wp-content\/uploads\/2023\/03\/world-map.png","type":"image\/png"}],"author":"griddb-admin","twitter_card":"summary_large_image","twitter_creator":"@GridDBCommunity","twitter_site":"@GridDBCommunity","twitter_misc":{"Written by":"griddb-admin","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#article","isPartOf":{"@id":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/"},"author":{"name":"griddb-admin","@id":"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233"},"headline":"Visualize Global Population Data with Mapbox, Node.js, and GridDB","datePublished":"2023-04-01T07:00:00+00:00","dateModified":"2025-11-13T20:56:32+00:00","mainEntityOfPage":{"@id":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/"},"wordCount":1842,"commentCount":0,"publisher":{"@id":"https:\/\/griddb.net\/en\/#organization"},"image":{"@id":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2023\/03\/world-map.png","articleSection":["Blog"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/","url":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/","name":"Visualize Global Population Data with Mapbox, Node.js, and GridDB | GridDB: Open Source Time Series Database for IoT","isPartOf":{"@id":"https:\/\/griddb.net\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#primaryimage"},"image":{"@id":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2023\/03\/world-map.png","datePublished":"2023-04-01T07:00:00+00:00","dateModified":"2025-11-13T20:56:32+00:00","description":"What We Will Build? This post will show you how to create a web-based map displaying world population data. The data is extracted from worldometers and","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb.net\/en\/blog\/visualize-global-population-data-with-mapbox-node-js-and-griddb\/#primaryimage","url":"\/wp-content\/uploads\/2023\/03\/world-map.png","contentUrl":"\/wp-content\/uploads\/2023\/03\/world-map.png","width":1920,"height":974},{"@type":"WebSite","@id":"https:\/\/griddb.net\/en\/#website","url":"https:\/\/griddb.net\/en\/","name":"GridDB: Open Source Time Series Database for IoT","description":"GridDB is an open source time-series database with the performance of NoSQL and convenience of SQL","publisher":{"@id":"https:\/\/griddb.net\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/griddb.net\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/griddb.net\/en\/#organization","name":"Fixstars","url":"https:\/\/griddb.net\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/","url":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","contentUrl":"https:\/\/griddb.net\/wp-content\/uploads\/2019\/04\/fixstars_logo_web_tagline.png","width":200,"height":83,"caption":"Fixstars"},"image":{"@id":"https:\/\/griddb.net\/en\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/griddbcommunity\/","https:\/\/x.com\/GridDBCommunity","https:\/\/www.linkedin.com\/company\/griddb-by-toshiba"]},{"@type":"Person","@id":"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233","name":"griddb-admin","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb.net\/en\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5bceca1cafc06886a7ba873e2f0a28011a1176c4dea59709f735b63ae30d0342?s=96&d=mm&r=g","caption":"griddb-admin"},"url":"https:\/\/griddb.net\/en\/author\/griddb-admin\/"}]}},"_links":{"self":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts\/46756","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/comments?post=46756"}],"version-history":[{"count":1,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts\/46756\/revisions"}],"predecessor-version":[{"id":51423,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/posts\/46756\/revisions\/51423"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/media\/29513"}],"wp:attachment":[{"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/media?parent=46756"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/categories?post=46756"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/griddb.net\/en\/wp-json\/wp\/v2\/tags?post=46756"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}