{"id":55175,"date":"2026-04-03T11:51:55","date_gmt":"2026-04-03T18:51:55","guid":{"rendered":"https:\/\/griddb.net\/?p=55175"},"modified":"2026-04-03T11:51:55","modified_gmt":"2026-04-03T18:51:55","slug":"watching-coastlines-vanish","status":"publish","type":"post","link":"https:\/\/www.griddb.net\/en\/blog\/watching-coastlines-vanish\/","title":{"rendered":"Watching Coastlines Vanish"},"content":{"rendered":"<h2 id=\"introduction\"><strong>Introduction<\/strong><\/h2>\n<p>\nGlobal climate change is accelerating sea level rise at an alarming rate\u2014averaging 3.3mm per year due to ocean warming and ice melt\u2014posing severe threats to coastal communities and infrastructure. The complex dynamics of tides, storm surges, and long-term sea level trends require advanced, real-time monitoring systems that can handle vast streams of temporal data with precision and speed.\n<\/p>\n<p>\nThis guide details the deployment of a robust time-series database using GridDB&#8217;s efficient columnar storage, integrated with NOAA&#8217;s oceanographic APIs, to build a scalable platform for coastal vulnerability assessment. We&#8217;ll walk through designing a high-throughput data ingestion pipeline that converts raw tidal data into practical insights, empowering proactive climate adaptation efforts.\n<\/p>\n<h2 id=\"why-griddb-for-time-series-in-coastal-monitoring\"><strong>Why GridDB for Time-Series in Coastal Monitoring?<\/strong><\/h2>\n<p>\nGridDB is an excellent choice for managing time-series data in coastal resilience projects because of its specialized features that handle high-volume, time-sensitive information effectively. Here&#8217;s why it stands out, explained in simple terms:\n<\/p>\n<ul>\n<li><strong>Speedy Data Handling<\/strong>: GridDB uses storage system that&#8217;s optimized for quick reads and writes, making it ideal for processing millions of real-time sea level readings from sensors without slowdowns\u2014crucial during fast-changing events like storms.<\/li>\n<li><strong>Scalability for Big Data<\/strong>: It can easily scale to store and query massive datasets from sources like NOAA APIs, allowing coastal monitoring systems to grow as more sensors are added without losing performance.<\/li>\n<li><strong>Time-Series Focus<\/strong>: Built-in support for timestamp-based queries lets you analyze trends over time (e.g., daily tides vs. yearly rises) efficiently, turning raw data into useful forecasts for flood risks or erosion.<\/li>\n<li><strong>Cost-Effective Integration<\/strong>: Easy to connect with tools like APIs and analytics software, reducing setup time and costs for building end-to-end systems that support climate adaptation decisions.<\/li>\n<\/ul>\n<h2 id=\"oceanographic-data-pipeline-architecture\"><strong>Oceanographic Data Pipeline Architecture<\/strong><\/h2>\n<p>\nContemporary coastal monitoring systems require ingestion and correlation of multiple oceanographic data streams to provide comprehensive situational awareness. Our implementation targets three primary data categories:\n<\/p>\n<p><strong>Real-Time Hydrostatic Measurements<\/strong>: High-frequency water level observations captured via pressure transducers and acoustic sensors, providing minute-resolution temporal data for immediate hazard detection and tidal analysis.<\/p>\n<p><strong>Statistical Aggregations<\/strong>: Monthly mean sea level calculations derived from harmonic tidal constituent analysis, essential for identifying long-term trends and separating anthropogenic signals from natural oceanographic cycles.<\/p>\n<p><strong>Geospatial Station Metadata<\/strong>: Comprehensive sensor network topology information including geographic coordinates, operational status, calibration parameters, and data quality metrics.<\/p>\n<p>\nThe NOAA Tides and Currents API ecosystem provides standardized access to these data streams:\n<\/p>\n<ul>\n<li><strong>Instantaneous Water Level Service<\/strong>: <code>https:\/\/tidesandcurrents.noaa.gov\/api\/datagetter<\/code> configured with high-resolution temporal sampling parameters<\/li>\n<li><strong>Long-Term Statistical Trends<\/strong>: Monthly aggregation endpoints providing climatological baseline data<\/li>\n<li><strong>Network Topology Service<\/strong>: <code>https:\/\/tidesandcurrents.noaa.gov\/mdapi\/v1.0\/webapi\/stations<\/code> delivering comprehensive sensor metadata<\/li>\n<\/ul>\n<h2 id=\"griddb-cloud-infrastructure-configuration\"><strong>GridDB Cloud Infrastructure Configuration<\/strong><\/h2>\n<h3 id=\"set-up-griddb-cloud\"><strong>Set Up GridDB Cloud<\/strong><\/h3>\n<p>\nFor this exercise, we will be using GridDB Cloud vesion. Start by visiting the <a href=\"https:\/\/griddb.net\/en\/\">GridDB Cloud<\/a> portal and <a href=\"[GridDB Cloud Free Plan | TOSHIBA DIGITAL SOLUTIONS CORPORATION](https:\/\/form.ict-toshiba.jp\/download_form_griddb_cloud_freeplan_e?utm_source=griddbnet&#038;utm_medium=topbanner\">signing up<\/a>) for an account.\n<\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/04\/logo.png\"><img fetchpriority=\"high\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/04\/logo.png\" alt=\"\" width=\"1280\" height=\"149\" class=\"aligncenter size-full wp-image-55180\" srcset=\"\/wp-content\/uploads\/2026\/04\/logo.png 1280w, \/wp-content\/uploads\/2026\/04\/logo-300x35.png 300w, \/wp-content\/uploads\/2026\/04\/logo-1024x119.png 1024w, \/wp-content\/uploads\/2026\/04\/logo-768x89.png 768w, \/wp-content\/uploads\/2026\/04\/logo-600x70.png 600w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/a><\/p>\n<p>\nBased on requirements, either the free plan or a paid plan can be selected for broader access. After registration ,an email will be sent containing essential details, including the Web API URL and login credentials.\n<\/p>\n<p>\nOnce the login details are received, log in to the Management GUI to access the cloud instance.\n<\/p>\n<h2 id=\"application-properties-configuration\"><strong>Application Properties Configuration<\/strong><\/h2>\n<p>\nThe <code>application.properties<\/code> file located in <code>src\/main\/resources<\/code> is crucial for configuring the application&#8217;s connection to GridDB Cloud and other external services. Here&#8217;s an example of the properties you would typically configure:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-properties\"># GridDB Cloud Connection Properties\r\ngriddb.rest.url=YOUR_GRIDDB_CLOUD_WEB_API_URL\r\ngriddb.api.key=YOUR_GRIDDB_CLOUD_API_KEY\r\ngriddb.cluster.name=YOUR_CLUSTER_NAME\r\ngriddb.username=YOUR_USERNAME\r\ngriddb.password=YOUR_PASSWORD\r\n\r\n# NOAA API Base URL (if applicable, for data fetching)\r\nnoaa.api.base.url=https:\/\/tidesandcurrents.noaa.gov\/api\/datagetter<\/code><\/pre>\n<\/div>\n<p>\nReplace the placeholder values (<code>YOUR_GRIDDB_CLOUD_WEB_API_URL<\/code>, <code>YOUR_GRIDDB_CLOUD_API_KEY<\/code>, etc.) with your actual GridDB Cloud credentials and cluster details. These properties ensure the application can securely connect to and interact with your GridDB instance.\n<\/p>\n<h3 id=\"development-environment-architecture\"><strong>Development Environment Architecture<\/strong><\/h3>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">$ \u2514\u2500\u2500\u2500my-griddb-app\r\n$     \u251c\u2500\u2500\u2500pom.xml\r\n$     \u251c\u2500\u2500\u2500src\r\n$     \u2502   \u251c\u2500\u2500\u2500main\r\n$     \u2502   \u2502   \u251c\u2500\u2500\u2500java\r\n$     \u2502   \u2502   \u2502   \u2514\u2500\u2500\u2500com\r\n$     \u2502   \u2502   \u2502       \u2514\u2500\u2500\u2500griddb\r\n$     \u2502   \u2502   \u2502           \u2514\u2500\u2500\u2500coastal\r\n$     \u2502   \u2502   \u2502               \u251c\u2500\u2500\u2500CoastalMonitorApplication.java\r\n$     \u2502   \u2502   \u2502               \u251c\u2500\u2500\u2500controller\r\n$     \u2502   \u2502   \u2502               \u2502   \u2514\u2500\u2500\u2500DashboardController.java\r\n$     \u2502   \u2502   \u2502               \u251c\u2500\u2500\u2500model\r\n$     \u2502   \u2502   \u2502               \u2502   \u251c\u2500\u2500\u2500MonthlyMeanData.java\r\n$     \u2502   \u2502   \u2502               \u2502   \u251c\u2500\u2500\u2500StationMetadata.java\r\n$     \u2502   \u2502   \u2502               \u2502   \u2514\u2500\u2500\u2500WaterLevelData.java\r\n$     \u2502   \u2502   \u2502               \u2514\u2500\u2500\u2500service\r\n$     \u2502   \u2502   \u2502                   \u251c\u2500\u2500\u2500DataSchedulerService.java\r\n$     \u2502   \u2502   \u2502                   \u251c\u2500\u2500\u2500GridDBService.java\r\n$     \u2502   \u2502   \u2502                   \u251c\u2500\u2500\u2500NOAADataService.java\r\n$     \u2502   \u2502   \u2502                   \u2514\u2500\u2500\u2500RestTemplateConfig.java\r\n$     \u2502   \u2502   \u2514\u2500\u2500\u2500resources\r\n$     \u2502   \u2502       \u251c\u2500\u2500\u2500application.properties\r\n$     \u2502   \u2502       \u2514\u2500\u2500\u2500templates\r\n$     \u2502   \u2502           \u2514\u2500\u2500\u2500dashboard.html\r\n$     \u2514\u2500\u2500\u2500target\r\n$         \u2514\u2500\u2500\u2500... (compiled classes, jar, etc.)<\/code><\/pre>\n<\/div>\n<p>\n###\n<\/p>\n<h4 id=\"maven-dependency-integration\"><strong>Maven Dependency Integration<\/strong><\/h4>\n<p>\nConfigure the project build system with GridDB client libraries:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-xml\">&lt;project xmlns=&quot;http:\/\/maven.apache.org\/POM\/4.0.0&quot;\r\n  xmlns:xsi=&quot;http:\/\/www.w3.org\/2001\/XMLSchema-instance&quot;\r\n  xsi:schemaLocation=&quot;http:\/\/maven.apache.org\/POM\/4.0.0 http:\/\/maven.apache.org\/maven-v4_0_0.xsd&quot;&gt;\r\n  &lt;modelVersion&gt;4.0.0&lt;\/modelVersion&gt;\r\n  &lt;groupId&gt;com.example&lt;\/groupId&gt;\r\n  &lt;artifactId&gt;my-griddb-app&lt;\/artifactId&gt;\r\n  &lt;version&gt;1.0-SNAPSHOT&lt;\/version&gt;\r\n  &lt;name&gt;my-griddb-app&lt;\/name&gt;\r\n  &lt;url&gt;http:\/\/maven.apache.org&lt;\/url&gt;\r\n\r\n  &lt;parent&gt;\r\n    &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n    &lt;artifactId&gt;spring-boot-starter-parent&lt;\/artifactId&gt;\r\n    &lt;version&gt;3.2.4&lt;\/version&gt;\r\n    &lt;relativePath \/&gt; &lt;!-- lookup parent from repository --&gt;\r\n  &lt;\/parent&gt;\r\n\r\n  &lt;properties&gt;\r\n    &lt;maven.compiler.source&gt;17&lt;\/maven.compiler.source&gt;\r\n    &lt;maven.compiler.target&gt;17&lt;\/maven.compiler.target&gt;\r\n  &lt;\/properties&gt;\r\n\r\n  &lt;dependencies&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;spring-boot-starter-actuator&lt;\/artifactId&gt;\r\n    &lt;\/dependency&gt;\r\n\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;spring-boot-starter-web&lt;\/artifactId&gt;\r\n      &lt;exclusions&gt;\r\n        &lt;exclusion&gt;\r\n          &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n          &lt;artifactId&gt;spring-boot-starter-logging&lt;\/artifactId&gt;\r\n        &lt;\/exclusion&gt;\r\n      &lt;\/exclusions&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;spring-boot-starter-test&lt;\/artifactId&gt;\r\n      &lt;scope&gt;test&lt;\/scope&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.springframework.boot&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;spring-boot-starter-thymeleaf&lt;\/artifactId&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;!-- JSON processing --&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.glassfish.jersey.core&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;jersey-client&lt;\/artifactId&gt;\r\n      &lt;version&gt;2.35&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.json&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;json&lt;\/artifactId&gt;\r\n      &lt;version&gt;20210307&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;com.fasterxml.jackson.core&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;jackson-databind&lt;\/artifactId&gt;\r\n      &lt;version&gt;2.15.0&lt;\/version&gt; &lt;!-- or the latest version --&gt;\r\n    &lt;\/dependency&gt;\r\n    &lt;!-- Lombok --&gt;\r\n    &lt;dependency&gt;\r\n      &lt;groupId&gt;org.projectlombok&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;lombok&lt;\/artifactId&gt;\r\n      &lt;optional&gt;true&lt;\/optional&gt;\r\n    &lt;\/dependency&gt;\r\n  &lt;dependency&gt;\r\n      &lt;groupId&gt;jakarta.annotation&lt;\/groupId&gt;\r\n      &lt;artifactId&gt;jakarta.annotation-api&lt;\/artifactId&gt;\r\n      &lt;version&gt;2.1.1&lt;\/version&gt;\r\n    &lt;\/dependency&gt;\r\n  &lt;\/dependencies&gt;\r\n  &lt;build&gt;\r\n    &lt;plugins&gt;\r\n      &lt;plugin&gt;\r\n        &lt;groupId&gt;org.apache.maven.plugins&lt;\/groupId&gt;\r\n        &lt;artifactId&gt;maven-compiler-plugin&lt;\/artifactId&gt;\r\n        &lt;configuration&gt;\r\n          &lt;annotationProcessorPaths&gt;\r\n            &lt;path&gt;\r\n              &lt;groupId&gt;org.projectlombok&lt;\/groupId&gt;\r\n              &lt;artifactId&gt;lombok&lt;\/artifactId&gt;\r\n              &lt;version&gt;${lombok.version}&lt;\/version&gt;\r\n            &lt;\/path&gt;\r\n          &lt;\/annotationProcessorPaths&gt;\r\n        &lt;\/configuration&gt;\r\n      &lt;\/plugin&gt;\r\n    &lt;\/plugins&gt;\r\n  &lt;\/build&gt;\r\n&lt;\/project&gt;<\/code><\/pre>\n<\/div>\n<h4 id=\"griddb-container-architecture\"><strong>GridDB Container Architecture<\/strong><\/h4>\n<p>\nOur implementation leverages three specialized Time Series Containers optimized for different temporal characteristics and query patterns:\n<\/p>\n<p><strong>Primary Time-Series Container (coastal_water_level)<\/strong><\/p>\n<p>\nDesigned for high-frequency sensor data ingestion with microsecond timestamp precision:\n<\/p>\n<ul>\n<li><code>timestamp<\/code> (TIMESTAMP) &#8211; Primary temporal index with automatic partitioning<\/li>\n<li><code>station_id<\/code> (STRING) &#8211; Composite index for spatial queries  <\/li>\n<li><code>station_name<\/code> (STRING) &#8211; Human-readable station identifier<\/li>\n<li><code>water_level<\/code> (DOUBLE) &#8211; Calibrated measurement in specified datum<\/li>\n<li><code>datum<\/code> (STRING) &#8211; Vertical reference system (MLLW, MSL, NAVD88)<\/li>\n<li><code>latitude<\/code> (DOUBLE) &#8211; WGS84 decimal degrees<\/li>\n<li><code>longitude<\/code> (DOUBLE) &#8211; WGS84 decimal degrees<\/li>\n<li><code>flags<\/code> (STRING) &#8211; Quality control and sensor status indicators<\/li>\n<\/ul>\n<p><strong>Statistical Aggregation Container (coastal_monthly_mean)<\/strong><\/p>\n<p>\nOptimized for climatological analysis and trend detection:\n<\/p>\n<ul>\n<li><code>month<\/code> (TIMESTAMP) &#8211; Monthly temporal partitioning key<\/li>\n<li><code>station_id<\/code> (STRING) &#8211; Station correlation index<\/li>\n<li><code>station_name<\/code> (STRING) &#8211; Station metadata<\/li>\n<li><code>mean_sea_level<\/code> (DOUBLE) &#8211; Statistically processed monthly average<\/li>\n<li><code>year<\/code> (INTEGER) &#8211; Temporal grouping field<\/li>\n<li><code>month_number<\/code> (INTEGER) &#8211; Numerical month for seasonal analysis<\/li>\n<li><code>latitude<\/code> (DOUBLE) &#8211; Geospatial coordinates<\/li>\n<li><code>longitude<\/code> (DOUBLE) &#8211; Geospatial coordinates<\/li>\n<\/ul>\n<p><strong>Metadata Container (coastal_stations)<\/strong><\/p>\n<p>\nStation configuration and operational status tracking:\n<\/p>\n<ul>\n<li><code>station_id<\/code> (STRING) &#8211; Unique station identifier<\/li>\n<li><code>station_name<\/code> (STRING) &#8211; Official station designation<\/li>\n<li><code>state<\/code> (STRING) &#8211; Administrative geographic region<\/li>\n<li><code>latitude<\/code> (DOUBLE) &#8211; Precise geographic positioning<\/li>\n<li><code>longitude<\/code> (DOUBLE) &#8211; Precise geographic positioning  <\/li>\n<li><code>region<\/code> (STRING) &#8211; Oceanographic zone classification<\/li>\n<li><code>is_active<\/code> (BOOL) &#8211; Operational status flag<\/li>\n<li><code>last_updated<\/code> (TIMESTAMP) &#8211; Maintenance tracking<\/li>\n<\/ul>\n<h2 id=\"real-time-data-ingestion-pipeline\"><strong>Real-Time Data Ingestion Pipeline<\/strong><\/h2>\n<p>\nThe heart of any real-time monitoring system lies in its ability to efficiently collect and process incoming data streams. For our coastal monitoring solution, this means seamlessly integrating with authoritative sources like NOAA to capture critical oceanographic measurements as they happen.\n<\/p>\n<h3 id=\"noaa-api-integration-service\"><strong>NOAA API Integration Service<\/strong><\/h3>\n<p>\nTo ensure our system always has the most up-to-date information on sea levels and coastal conditions, we&#8217;ve developed a dedicated service for interacting with NOAA&#8217;s comprehensive APIs. This service is designed for resilience, handling network fluctuations and data retrieval with robust error management, ensuring a continuous flow of vital data into our system.\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">package com.griddb.coastal.service;\r\n\r\nimport com.griddb.coastal.model.WaterLevelData;\r\nimport com.griddb.coastal.model.MonthlyMeanData;\r\nimport com.griddb.coastal.model.StationMetadata;\r\nimport org.json.JSONArray;\r\nimport org.json.JSONObject;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.beans.factory.annotation.Value;\r\nimport org.springframework.stereotype.Service;\r\n\r\nimport java.io.BufferedReader;\r\nimport java.io.InputStreamReader;\r\nimport java.net.HttpURLConnection;\r\nimport java.net.URL;\r\nimport java.time.LocalDate;\r\nimport java.time.LocalDateTime;\r\nimport java.time.format.DateTimeFormatter;\r\nimport java.util.*;\r\n\r\n@Service\r\npublic class NOAADataService {\r\n\r\n    private static final Logger logger = LoggerFactory.getLogger(NOAADataService.class);\r\n\r\n    @Value(&quot;${noaa.api.base.url}&quot;)\r\n    private String noaaBaseUrl;\r\n\r\n    @Value(&quot;${noaa.api.metadata.url}&quot;)\r\n    private String noaaMetadataUrl;\r\n\r\n    @Value(&quot;${noaa.api.application}&quot;)\r\n    private String applicationName;\r\n\r\n    @Value(&quot;${noaa.stations}&quot;)\r\n    private String stationsConfig;\r\n\r\n    private Map&lt;String, StationMetadata&gt; stationCache = new HashMap&lt;&gt;();\r\n\r\n    \/**\r\n     * Fetch latest water level data for a station\r\n     *\/\r\n    public List&lt;WaterLevelData&gt; fetchLatestWaterLevels(String stationId) {\r\n        List&lt;WaterLevelData&gt; waterLevels = new ArrayList&lt;&gt;();\r\n\r\n        try {\r\n            String urlStr = String.format(&quot;%s?product=water_level&amp;application=%s&amp;station=%s&amp;date=latest&amp;datum=MLLW&amp;time_zone=gmt&amp;units=metric&amp;format=json&quot;,\r\n                    noaaBaseUrl, applicationName, stationId);\r\n\r\n            logger.info(&quot;Fetching latest water levels from: {}&quot;, urlStr);\r\n\r\n            String response = makeHttpRequest(urlStr);\r\n            JSONObject jsonResponse = new JSONObject(response);\r\n\r\n            if (jsonResponse.has(&quot;data&quot;)) {\r\n                JSONArray dataArray = jsonResponse.getJSONArray(&quot;data&quot;);\r\n                StationMetadata station = getOrFetchStationMetadata(stationId);\r\n\r\n                for (int i = 0; i &lt; dataArray.length(); i++) {\r\n                    JSONObject dataPoint = dataArray.getJSONObject(i);\r\n\r\n                    \/\/ NOAA format: {&quot;t&quot;: &quot;yyyy-MM-dd HH:mm&quot;, &quot;v&quot;: &quot;x.xxx&quot;, &quot;f&quot;: &quot;...&quot;}\r\n                    String timestamp = dataPoint.getString(&quot;t&quot;);\r\n                    double waterLevel = Double.parseDouble(dataPoint.getString(&quot;v&quot;));\r\n                    String flags = dataPoint.optString(&quot;f&quot;, &quot;&quot;);\r\n\r\n                    LocalDateTime dateTime = LocalDateTime.parse(timestamp, \r\n                        DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd HH:mm&quot;));\r\n\r\n                    WaterLevelData wld = new WaterLevelData(\r\n                        stationId, \r\n                        station.getStationName(),\r\n                        dateTime,\r\n                        waterLevel,\r\n                        &quot;MLLW&quot;,\r\n                        station.getLatitude(),\r\n                        station.getLongitude(),\r\n                        flags\r\n                    );\r\n                    waterLevels.add(wld);\r\n                }\r\n            }\r\n\r\n            logger.info(&quot;Fetched {} water level readings for station {}&quot;, waterLevels.size(), stationId);\r\n\r\n        } catch (Exception e) {\r\n            logger.error(&quot;Error fetching water level data for station {}: {}&quot;, stationId, e.getMessage());\r\n        }\r\n\r\n        return waterLevels;\r\n    }\r\n\r\n    \/**\r\n     * Fetch historical water level data (last 7 days)\r\n     *\/\r\n    public List&lt;WaterLevelData&gt; fetchRecentWaterLevels(String stationId, int days) {\r\n        List&lt;WaterLevelData&gt; waterLevels = new ArrayList&lt;&gt;();\r\n\r\n        try {\r\n            LocalDate endDate = LocalDate.now();\r\n            LocalDate startDate = endDate.minusDays(days);\r\n\r\n            String urlStr = String.format(&quot;%s?product=water_level&amp;application=%s&amp;station=%s&amp;begin_date=%s&amp;end_date=%s&amp;datum=MLLW&amp;time_zone=gmt&amp;units=metric&amp;format=json&quot;,\r\n                    noaaBaseUrl, applicationName, stationId, \r\n                    startDate.format(DateTimeFormatter.ofPattern(&quot;yyyyMMdd&quot;)),\r\n                    endDate.format(DateTimeFormatter.ofPattern(&quot;yyyyMMdd&quot;)));\r\n\r\n            logger.info(&quot;Fetching recent water levels from: {}&quot;, urlStr);\r\n\r\n            String response = makeHttpRequest(urlStr);\r\n            JSONObject jsonResponse = new JSONObject(response);\r\n\r\n            if (jsonResponse.has(&quot;data&quot;)) {\r\n                JSONArray dataArray = jsonResponse.getJSONArray(&quot;data&quot;);\r\n                StationMetadata station = getOrFetchStationMetadata(stationId);\r\n\r\n                for (int i = 0; i &lt; dataArray.length(); i++) {\r\n                    JSONObject dataPoint = dataArray.getJSONObject(i);\r\n\r\n                    String timestamp = dataPoint.getString(&quot;t&quot;);\r\n                    double waterLevel = Double.parseDouble(dataPoint.getString(&quot;v&quot;));\r\n                    String flags = dataPoint.optString(&quot;f&quot;, &quot;&quot;);\r\n\r\n                    LocalDateTime dateTime = LocalDateTime.parse(timestamp, \r\n                        DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd HH:mm&quot;));\r\n\r\n                    WaterLevelData wld = new WaterLevelData(\r\n                        stationId, \r\n                        station.getStationName(),\r\n                        dateTime,\r\n                        waterLevel,\r\n                        &quot;MLLW&quot;,\r\n                        station.getLatitude(),\r\n                        station.getLongitude(),\r\n                        flags\r\n                    );\r\n                    waterLevels.add(wld);\r\n                }\r\n            }\r\n\r\n            logger.info(&quot;Fetched {} historical water level readings for station {}&quot;, waterLevels.size(), stationId);\r\n\r\n        } catch (Exception e) {\r\n            logger.error(&quot;Error fetching recent water level data for station {}: {}&quot;, stationId, e.getMessage());\r\n        }\r\n\r\n        return waterLevels;\r\n    }\r\n\r\n    \/**\r\n     * Fetch monthly mean data for long-term trend analysis\r\n     *\/\r\n    public List&lt;MonthlyMeanData&gt; fetchMonthlyMeanData(String stationId, int years) {\r\n        List&lt;MonthlyMeanData&gt; monthlyData = new ArrayList&lt;&gt;();\r\n\r\n        try {\r\n            LocalDate endDate = LocalDate.now();\r\n            LocalDate startDate = endDate.minusYears(years);\r\n\r\n            String urlStr = String.format(&quot;%s?product=monthly_mean&amp;application=%s&amp;station=%s&amp;begin_date=%s&amp;end_date=%s&amp;datum=MSL&amp;time_zone=gmt&amp;units=metric&amp;format=json&quot;,\r\n                    noaaBaseUrl, applicationName, stationId, \r\n                    startDate.format(DateTimeFormatter.ofPattern(&quot;yyyyMMdd&quot;)),\r\n                    endDate.format(DateTimeFormatter.ofPattern(&quot;yyyyMMdd&quot;)));\r\n\r\n            logger.info(&quot;Fetching monthly mean data from: {}&quot;, urlStr);\r\n\r\n            String response = makeHttpRequest(urlStr);\r\n            JSONObject jsonResponse = new JSONObject(response);\r\n\r\n            if (jsonResponse.has(&quot;data&quot;)) {\r\n                JSONArray dataArray = jsonResponse.getJSONArray(&quot;data&quot;);\r\n                StationMetadata station = getOrFetchStationMetadata(stationId);\r\n\r\n                for (int i = 0; i &lt; dataArray.length(); i++) {\r\n                    JSONObject dataPoint = dataArray.getJSONObject(i);\r\n\r\n                    \/\/ NOAA format: {&quot;year&quot;: &quot;YYYY&quot;, &quot;month&quot;: &quot;MM&quot;, &quot;MSL&quot;: &quot;x.xxx&quot;}\r\n                    int year = Integer.parseInt(dataPoint.getString(&quot;year&quot;));\r\n                    int monthNumber = Integer.parseInt(dataPoint.getString(&quot;month&quot;));\r\n                    double meanLevel = Double.parseDouble(dataPoint.getString(&quot;MSL&quot;));\r\n\r\n                    LocalDate month = LocalDate.of(year, monthNumber, 1);\r\n\r\n                    MonthlyMeanData mmd = new MonthlyMeanData(\r\n                        stationId,\r\n                        station.getStationName(),\r\n                        month,\r\n                        meanLevel,\r\n                        year,\r\n                        monthNumber,\r\n                        station.getLatitude(),\r\n                        station.getLongitude()\r\n                    );\r\n                    monthlyData.add(mmd);\r\n                }\r\n            }\r\n\r\n            logger.info(&quot;Fetched {} monthly mean readings for station {}&quot;, monthlyData.size(), stationId);\r\n\r\n        } catch (Exception e) {\r\n            logger.error(&quot;Error fetching monthly mean data for station {}: {}&quot;, stationId, e.getMessage());\r\n        }\r\n\r\n        return monthlyData;\r\n    }\r\n\r\n    \/**\r\n     * Get configured monitoring stations\r\n     *\/\r\n    public List&lt;StationMetadata&gt; getConfiguredStations() {\r\n        List&lt;StationMetadata&gt; stations = new ArrayList&lt;&gt;();\r\n\r\n        String[] stationConfigs = stationsConfig.split(&quot;;&quot;);\r\n        for (String config : stationConfigs) {\r\n            String[] parts = config.split(&quot;,&quot;);\r\n            if (parts.length &gt;= 6) {\r\n                StationMetadata station = StationMetadata.builder()\r\n                    .stationId(parts[0].trim())\r\n                    .stationName(parts[1].trim())\r\n                    .state(parts[2].trim())\r\n                    .latitude(Double.parseDouble(parts[3].trim()))\r\n                    .longitude(Double.parseDouble(parts[4].trim()))\r\n                    .isActive(Boolean.parseBoolean(parts[5].trim()))\r\n                    .build();\r\n                stations.add(station);\r\n            }\r\n        }\r\n\r\n        return stations;\r\n    }\r\n\r\n    \/**\r\n     * Get or fetch station metadata\r\n     *\/\r\n    private StationMetadata getOrFetchStationMetadata(String stationId) {\r\n        if (stationCache.containsKey(stationId)) {\r\n            return stationCache.get(stationId);\r\n        }\r\n\r\n        \/\/ Return default station info if not in cache\r\n        StationMetadata station = StationMetadata.builder()\r\n            .stationId(stationId)\r\n            .stationName(&quot;Station &quot; + stationId)\r\n            .latitude(40.0) \/\/ Default coordinates\r\n            .longitude(-74.0)\r\n            .build();\r\n        stationCache.put(stationId, station);\r\n\r\n        return station;\r\n    }\r\n\r\n    \/**\r\n     * Make HTTP request to NOAA API\r\n     *\/\r\n    private String makeHttpRequest(String urlStr) throws Exception {\r\n        URL url = new URL(urlStr);\r\n        HttpURLConnection conn = (HttpURLConnection) url.openConnection();\r\n        conn.setRequestMethod(&quot;GET&quot;);\r\n        conn.setRequestProperty(&quot;User-Agent&quot;, &quot;GridDB-CoastalMonitor\/1.0&quot;);\r\n\r\n        int responseCode = conn.getResponseCode();\r\n        if (responseCode != 200) {\r\n            throw new RuntimeException(&quot;HTTP Error: &quot; + responseCode);\r\n        }\r\n\r\n        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));\r\n        StringBuilder response = new StringBuilder();\r\n        String line;\r\n\r\n        while ((line = reader.readLine()) != null) {\r\n            response.append(line);\r\n        }\r\n        reader.close();\r\n\r\n        String responseStr = response.toString();\r\n        logger.info(&quot;NOAA API Response for {}: {}&quot;, urlStr, responseStr);\r\n        if (responseStr.trim().isEmpty()) {\r\n            return &quot;{}&quot;;\r\n        }\r\n        return responseStr;\r\n    }\r\n}<\/code><\/pre>\n<\/div>\n<h3 id=\"data-transformation-and-persistence-layer\"><strong>Data Transformation and Persistence Layer<\/strong><\/h3>\n<p>\nOnce raw data is acquired, it must be  prepared for storage and analysis. This layer is dedicated to transforming the diverse incoming data into a standardized, clean, and enriched format, ensuring its integrity and usability within GridDB.\n<\/p>\n<p>\nThe NOAA APIs provide data in various JSON structures. Before this data can be effectively stored and utilized in GridDB, it undergoes a  transformation process. This ensures consistency, handles potential missing values, and converts raw measurements into a format optimized for our time-series database.\n<\/p>\n<p>\nExample NOAA API response structure:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-json\">{\r\n  &quot;metadata&quot;: {\r\n    &quot;id&quot;: &quot;8518750&quot;,\r\n    &quot;name&quot;: &quot;The Battery&quot;, \r\n    &quot;lat&quot;: &quot;40.7012&quot;,\r\n    &quot;lon&quot;: &quot;-74.0137&quot;,\r\n    &quot;url&quot;: &quot;https:\/\/tidesandcurrents.noaa.gov\/stationhome.html?id=8518750&quot;\r\n  },\r\n  &quot;data&quot;: [\r\n    {\r\n      &quot;t&quot;: &quot;2025-08-23 10:00&quot;,\r\n      &quot;v&quot;: &quot;0.193&quot;, \r\n      &quot;s&quot;: &quot;0.000&quot;,\r\n      &quot;f&quot;: &quot;0,0,0,0&quot;,\r\n      &quot;q&quot;: &quot;p&quot;\r\n    }\r\n  ]\r\n}<\/code><\/pre>\n<\/div>\n<p>\nThe ingestion service performs automatic data type conversions, handles missing values through interpolation algorithms, and maintains data lineage for audit trails.\n<\/p>\n<p>\nFor persistence, the transformed data is stored in GridDB using its REST-based API. Each record is written into a time-series container. The REST API allows applications to send JSON payloads directly to GridDB, where the data is indexed by timestamp and made available for queries and analysis.\n<\/p>\n<h2 id=\"interactive-visualization-and-analytics-dashboard\"><strong>Interactive Visualization and Analytics Dashboard<\/strong><\/h2>\n<p>\nA powerful monitoring system is incomplete without a clear and intuitive way to visualize its data. Our interactive dashboard transforms raw oceanographic measurements into actionable insights, providing a dynamic view of coastal changes and trends. The dashboard retrieves data directly from GridDB, which efficiently serves time-series queries, ensuring that visualizations update quickly as new measurements arrive.\n<\/p>\n<h3 id=\"web-application-controller-layer\"><strong>Web Application Controller Layer<\/strong><\/h3>\n<p>\nThe presentation tier implements RESTful endpoints serving both human-readable dashboards and machine-readable APIs for external system integration:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-java\">package com.griddb.coastal.controller;\r\n\r\nimport com.griddb.coastal.service.NOAADataService;\r\nimport com.griddb.coastal.service.GridDBService;\r\nimport com.griddb.coastal.service.DataSchedulerService;\r\nimport com.griddb.coastal.model.StationMetadata;\r\nimport org.json.JSONArray;\r\nimport org.json.JSONObject;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.http.ResponseEntity;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.ui.Model;\r\nimport org.springframework.web.bind.annotation.*;\r\n\r\nimport java.util.List;\r\n\r\n@Controller\r\npublic class DashboardController {\r\n\r\n    private static final Logger logger = LoggerFactory.getLogger(DashboardController.class);\r\n\r\n    @Autowired\r\n    private NOAADataService noaaDataService;\r\n\r\n    @Autowired\r\n    private GridDBService gridDBService;\r\n\r\n    @Autowired\r\n    private DataSchedulerService schedulerService;\r\n\r\n    \/**\r\n     * Main dashboard page\r\n     *\/\r\n    @GetMapping(&quot;\/&quot;)\r\n    public String dashboard(Model model) {\r\n        logger.info(&quot;Rendering main dashboard&quot;);\r\n\r\n        List&lt;StationMetadata&gt; stations = noaaDataService.getConfiguredStations();\r\n        model.addAttribute(&quot;stations&quot;, stations);\r\n        model.addAttribute(&quot;title&quot;, &quot;Watching Coastlines Vanish&quot;);\r\n        model.addAttribute(&quot;subtitle&quot;, &quot;Real-time Coastal Monitoring with GridDB Time-Series&quot;);\r\n\r\n        return &quot;dashboard&quot;;\r\n    }\r\n\r\n    \/**\r\n     * Get latest water levels for a specific station (JSON API)\r\n     *\/\r\n    @GetMapping(&quot;\/api\/water-levels\/{stationId}&quot;)\r\n    @ResponseBody\r\n    public ResponseEntity&lt;String&gt; getWaterLevels(@PathVariable String stationId, \r\n                                               @RequestParam(defaultValue = &quot;24&quot;) int hours) {\r\n        try {\r\n            String data = gridDBService.queryLatestWaterLevels(stationId, hours);\r\n            return ResponseEntity.ok(data);\r\n        } catch (Exception e) {\r\n            logger.error(&quot;Error fetching water levels for station {}: {}&quot;, stationId, e.getMessage());\r\n            return ResponseEntity.internalServerError().body(&quot;{&quot;error&quot;: &quot;&quot; + e.getMessage() + &quot;}&quot;);\r\n        }\r\n    }\r\n\r\n    \/**\r\n     * Get monthly trends for sea level rise analysis (JSON API)\r\n     *\/\r\n    @GetMapping(&quot;\/api\/monthly-trends\/{stationId}&quot;)\r\n    @ResponseBody\r\n    public ResponseEntity&lt;String&gt; getMonthlyTrends(@PathVariable String stationId,\r\n                                                  @RequestParam(defaultValue = &quot;10&quot;) int years) {\r\n        try {\r\n            String data = gridDBService.queryMonthlyTrends(stationId, years);\r\n            return ResponseEntity.ok(data);\r\n        } catch (Exception e) {\r\n            logger.error(&quot;Error fetching monthly trends for station {}: {}&quot;, stationId, e.getMessage());\r\n            return ResponseEntity.internalServerError().body(&quot;{&quot;error&quot;: &quot;&quot; + e.getMessage() + &quot;}&quot;);\r\n        }\r\n    }\r\n\r\n    \/**\r\n     * Get all stations metadata (JSON API)\r\n     *\/\r\n    @GetMapping(&quot;\/api\/stations&quot;)\r\n    @ResponseBody\r\n    public ResponseEntity&lt;List&lt;StationMetadata&gt;&gt; getAllStations() {\r\n        try {\r\n            List&lt;StationMetadata&gt; stations = noaaDataService.getConfiguredStations();\r\n            return ResponseEntity.ok(stations);\r\n        } catch (Exception e) {\r\n            logger.error(&quot;Error fetching stations: {}&quot;, e.getMessage());\r\n            return ResponseEntity.internalServerError().build();\r\n        }\r\n    }\r\n\r\n    \/**\r\n     * Get aggregated data for all stations dashboard\r\n     *\/\r\n    @GetMapping(&quot;\/api\/dashboard-data&quot;)\r\n    @ResponseBody\r\n    public ResponseEntity&lt;String&gt; getDashboardData() {\r\n        try {\r\n            JSONObject dashboardData = new JSONObject();\r\n            JSONArray stationsData = new JSONArray();\r\n\r\n            List&lt;StationMetadata&gt; stations = noaaDataService.getConfiguredStations();\r\n\r\n            for (StationMetadata station : stations) {\r\n                JSONObject stationInfo = new JSONObject();\r\n                stationInfo.put(&quot;stationId&quot;, station.getStationId());\r\n                stationInfo.put(&quot;stationName&quot;, station.getStationName());\r\n                stationInfo.put(&quot;state&quot;, station.getState());\r\n                stationInfo.put(&quot;latitude&quot;, station.getLatitude());\r\n                stationInfo.put(&quot;longitude&quot;, station.getLongitude());\r\n\r\n                \/\/ Get latest water level\r\n                String latestDataString = gridDBService.queryLatestWaterLevels(station.getStationId(), 1);\r\n                JSONObject latestDataObject = new JSONObject(latestDataString);\r\n                stationInfo.put(&quot;latestWaterLevel&quot;, latestDataObject);\r\n\r\n                \/\/ Get monthly trend (last 2 years for quick overview)\r\n                String trendDataString = gridDBService.queryMonthlyTrends(station.getStationId(), 2);\r\n                JSONObject trendDataObject = new JSONObject(trendDataString);\r\n                logger.info(&quot;Monthly Trend Data for {}: {}&quot;, station.getStationId(), trendDataObject.toString());\r\n                stationInfo.put(&quot;monthlyTrend&quot;, trendDataObject);\r\n\r\n                stationsData.put(stationInfo);\r\n            }\r\n\r\n            dashboardData.put(&quot;stations&quot;, stationsData);\r\n            dashboardData.put(&quot;lastUpdated&quot;, System.currentTimeMillis());\r\n            dashboardData.put(&quot;totalStations&quot;, stations.size());\r\n\r\n            return ResponseEntity.ok(dashboardData.toString());\r\n\r\n        } catch (Exception e) {\r\n            logger.error(&quot;Error generating dashboard data: {}&quot;, e.getMessage());\r\n            return ResponseEntity.internalServerError().body(&quot;{&quot;error&quot;: &quot;&quot; + e.getMessage() + &quot;}&quot;);\r\n        }\r\n    }\r\n\r\n    \/**\r\n     * Manual data collection trigger (for testing\/admin)\r\n     *\/\r\n    @PostMapping(&quot;\/api\/trigger-collection&quot;)\r\n    @ResponseBody\r\n    public ResponseEntity&lt;String&gt; triggerDataCollection() {\r\n        try {\r\n            schedulerService.triggerDataCollection();\r\n            JSONObject response = new JSONObject();\r\n            response.put(&quot;status&quot;, &quot;success&quot;);\r\n            response.put(&quot;message&quot;, &quot;Data collection triggered successfully&quot;);\r\n            response.put(&quot;timestamp&quot;, System.currentTimeMillis());\r\n\r\n            return ResponseEntity.ok(response.toString());\r\n        } catch (Exception e) {\r\n            logger.error(&quot;Error triggering data collection: {}&quot;, e.getMessage());\r\n            return ResponseEntity.internalServerError().body(&quot;{&quot;error&quot;: &quot;&quot; + e.getMessage() + &quot;}&quot;);\r\n        }\r\n    }\r\n\r\n    \/**\r\n     * Manual monthly data update trigger\r\n     *\/\r\n    @PostMapping(&quot;\/api\/trigger-monthly-update&quot;)\r\n    @ResponseBody\r\n    public ResponseEntity&lt;String&gt; triggerMonthlyUpdate() {\r\n        try {\r\n            schedulerService.triggerMonthlyUpdate();\r\n            JSONObject response = new JSONObject();\r\n            response.put(&quot;status&quot;, &quot;success&quot;);\r\n            response.put(&quot;message&quot;, &quot;Monthly data update triggered successfully&quot;);\r\n            response.put(&quot;timestamp&quot;, System.currentTimeMillis());\r\n\r\n            return ResponseEntity.ok(response.toString());\r\n        } catch (Exception e) {\r\n            logger.error(&quot;Error triggering monthly update: {}&quot;, e.getMessage());\r\n            return ResponseEntity.internalServerError().body(&quot;{&quot;error&quot;: &quot;&quot; + e.getMessage() + &quot;}&quot;);\r\n        }\r\n    }\r\n\r\n    \/**\r\n     * Health check endpoint\r\n     *\/\r\n    @GetMapping(&quot;\/api\/health&quot;)\r\n    @ResponseBody\r\n    public ResponseEntity&lt;String&gt; healthCheck() {\r\n        JSONObject health = new JSONObject();\r\n        health.put(&quot;status&quot;, &quot;UP&quot;);\r\n        health.put(&quot;application&quot;, &quot;Coastal Monitor&quot;);\r\n        health.put(&quot;timestamp&quot;, System.currentTimeMillis());\r\n        health.put(&quot;griddb&quot;, &quot;Connected&quot;);\r\n        health.put(&quot;noaa&quot;, &quot;Available&quot;);\r\n\r\n        return ResponseEntity.ok(health.toString());\r\n    }\r\n}<\/code><\/pre>\n<\/div>\n<p>\nThe dashboard retrieves data from GridDB using paging-based REST APIs, which allow large time-series datasets to be read in smaller chunks. This makes queries efficient and ensures the visualizations can update smoothly as new measurements arrive.\n<\/p>\n<h2 id=\"application-deployment\"><strong>Application Deployment<\/strong><\/h2>\n<h3 id=\"build-and-execution-pipeline\"><strong>Build and Execution Pipeline<\/strong><\/h3>\n<p>\nDeploy the complete monitoring system using Maven&#8217;s integrated build lifecycle:\n<\/p>\n<div class=\"clipboard\">\n<pre><code class=\"language-sh\">$ mvn clean install &amp;&amp; mvn spring-boot:run <\/code><\/pre>\n<\/div>\n<p>\nAccess the operational dashboard through standard HTTP protocols: <code>http:\/\/localhost:8080\/<\/code>. Once the system is running, it continuously fetches live data and updates the dashboards with real-time insights.\n<\/p>\n<p>\nThis chart displays real-time and historical water level data, providing a clear visualization of coastal conditions. Specifically, it shows:\n<\/p>\n<ul>\n<li><strong>Real-time Water Level (m)<\/strong>: Instantaneous water level measurements over time, reflecting current tidal and environmental conditions. This data is crucial for immediate hazard detection, such as storm surges and unusually high tides, allowing for timely warnings and emergency responses to protect coastal communities and infrastructure.<\/li>\n<li><strong>Monthly Mean Water Level (m)<\/strong>: The average monthly sea level, which helps in identifying long-term trends and assessing sea level rise. By analyzing these long-term trends, coastal planners and scientists can understand the rate of sea level rise, predict future impacts, and develop strategies for climate adaptation, including land-use planning, infrastructure development, and ecosystem restoration. The combination of real-time and historical data provides a comprehensive view, enabling both immediate operational decisions and long-term strategic planning for coastal resilience.<\/li>\n<\/ul>\n<p><<a href=\"\/wp-content\/uploads\/2026\/04\/img3.png\"><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/04\/img3.png\" alt=\"\" width=\"2512\" height=\"1740\" class=\"aligncenter size-full wp-image-55179\" srcset=\"\/wp-content\/uploads\/2026\/04\/img3.png 2512w, \/wp-content\/uploads\/2026\/04\/img3-300x208.png 300w, \/wp-content\/uploads\/2026\/04\/img3-1024x709.png 1024w, \/wp-content\/uploads\/2026\/04\/img3-768x532.png 768w, \/wp-content\/uploads\/2026\/04\/img3-1536x1064.png 1536w, \/wp-content\/uploads\/2026\/04\/img3-2048x1419.png 2048w, \/wp-content\/uploads\/2026\/04\/img3-600x416.png 600w\" sizes=\"(max-width: 2512px) 100vw, 2512px\" \/><\/a><\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/04\/img2.png\"><img decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/04\/img2.png\" alt=\"\" width=\"2318\" height=\"1738\" class=\"aligncenter size-full wp-image-55178\" srcset=\"\/wp-content\/uploads\/2026\/04\/img2.png 2318w, \/wp-content\/uploads\/2026\/04\/img2-300x225.png 300w, \/wp-content\/uploads\/2026\/04\/img2-1024x768.png 1024w, \/wp-content\/uploads\/2026\/04\/img2-768x576.png 768w, \/wp-content\/uploads\/2026\/04\/img2-1536x1152.png 1536w, \/wp-content\/uploads\/2026\/04\/img2-2048x1536.png 2048w, \/wp-content\/uploads\/2026\/04\/img2-600x450.png 600w\" sizes=\"(max-width: 2318px) 100vw, 2318px\" \/><\/a><\/p>\n<p><a href=\"\/wp-content\/uploads\/2026\/04\/img1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"\/wp-content\/uploads\/2026\/04\/img1.png\" alt=\"\" width=\"2262\" height=\"1036\" class=\"aligncenter size-full wp-image-55177\" srcset=\"\/wp-content\/uploads\/2026\/04\/img1.png 2262w, \/wp-content\/uploads\/2026\/04\/img1-300x137.png 300w, \/wp-content\/uploads\/2026\/04\/img1-1024x469.png 1024w, \/wp-content\/uploads\/2026\/04\/img1-768x352.png 768w, \/wp-content\/uploads\/2026\/04\/img1-1536x703.png 1536w, \/wp-content\/uploads\/2026\/04\/img1-2048x938.png 2048w, \/wp-content\/uploads\/2026\/04\/img1-600x275.png 600w\" sizes=\"(max-width: 2262px) 100vw, 2262px\" \/><\/a><\/p>\n<h2 id=\"conclusion\"><strong>Conclusion<\/strong><\/h2>\n<p>\nThis project demonstrates how GridDB effectively monitors coastal changes in real-time. By integrating with NOAA&#8217;s data streams and processing millions of sea level measurements, the system converts raw data into actionable insights on evolving coastlines. GridDB&#8217;s strength lies in managing time-series data at scale, avoiding traditional databases&#8217; performance issues, and enabling trend detection and anomaly identification during storms\u2014delivering essential information for coastal planners.\n<\/p>\n<p>\nAs sea levels rise and storms intensify, reliable data access is vital for infrastructure and emergency decisions. The GridDB solution shows that environmental challenges can be addressed effectively with the right tool, without unnecessary complexity.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Global climate change is accelerating sea level rise at an alarming rate\u2014averaging 3.3mm per year due to ocean warming and ice melt\u2014posing severe threats to coastal communities and infrastructure. The complex dynamics of tides, storm surges, and long-term sea level trends require advanced, real-time monitoring systems that can handle vast streams of temporal data [&hellip;]<\/p>\n","protected":false},"author":41,"featured_media":55181,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[121],"tags":[],"class_list":["post-55175","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>Watching Coastlines Vanish | GridDB: Open Source Time Series Database for IoT<\/title>\n<meta name=\"description\" content=\"Introduction Global climate change is accelerating sea level rise at an alarming rate\u2014averaging 3.3mm per year due to ocean warming and ice melt\u2014posing\" \/>\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-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Watching Coastlines Vanish | GridDB: Open Source Time Series Database for IoT\" \/>\n<meta property=\"og:description\" content=\"Introduction Global climate change is accelerating sea level rise at an alarming rate\u2014averaging 3.3mm per year due to ocean warming and ice melt\u2014posing\" \/>\n<meta property=\"og:url\" content=\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/\" \/>\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=\"2026-04-03T18:51:55+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.griddb.net\/wp-content\/uploads\/2019\/04\/503.gif\" \/>\n\t<meta property=\"og:image:width\" content=\"450\" \/>\n\t<meta property=\"og:image:height\" content=\"400\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/gif\" \/>\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=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/\"},\"author\":{\"name\":\"griddb-admin\",\"@id\":\"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233\"},\"headline\":\"Watching Coastlines Vanish\",\"datePublished\":\"2026-04-03T18:51:55+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/\"},\"wordCount\":1342,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/griddb.net\/en\/#organization\"},\"image\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2026\/04\/coastal_monitoring_featured_image.svg\",\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/\",\"url\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/\",\"name\":\"Watching Coastlines Vanish | GridDB: Open Source Time Series Database for IoT\",\"isPartOf\":{\"@id\":\"https:\/\/griddb.net\/en\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#primaryimage\"},\"thumbnailUrl\":\"\/wp-content\/uploads\/2026\/04\/coastal_monitoring_featured_image.svg\",\"datePublished\":\"2026-04-03T18:51:55+00:00\",\"description\":\"Introduction Global climate change is accelerating sea level rise at an alarming rate\u2014averaging 3.3mm per year due to ocean warming and ice melt\u2014posing\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#primaryimage\",\"url\":\"\/wp-content\/uploads\/2026\/04\/coastal_monitoring_featured_image.svg\",\"contentUrl\":\"\/wp-content\/uploads\/2026\/04\/coastal_monitoring_featured_image.svg\",\"width\":680,\"height\":390},{\"@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:\/\/www.griddb.net\/en\/author\/griddb-admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Watching Coastlines Vanish | GridDB: Open Source Time Series Database for IoT","description":"Introduction Global climate change is accelerating sea level rise at an alarming rate\u2014averaging 3.3mm per year due to ocean warming and ice melt\u2014posing","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-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/","og_locale":"en_US","og_type":"article","og_title":"Watching Coastlines Vanish | GridDB: Open Source Time Series Database for IoT","og_description":"Introduction Global climate change is accelerating sea level rise at an alarming rate\u2014averaging 3.3mm per year due to ocean warming and ice melt\u2014posing","og_url":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/","og_site_name":"GridDB: Open Source Time Series Database for IoT","article_publisher":"https:\/\/www.facebook.com\/griddbcommunity\/","article_published_time":"2026-04-03T18:51:55+00:00","og_image":[{"width":450,"height":400,"url":"https:\/\/www.griddb.net\/wp-content\/uploads\/2019\/04\/503.gif","type":"image\/gif"}],"author":"griddb-admin","twitter_card":"summary_large_image","twitter_creator":"@GridDBCommunity","twitter_site":"@GridDBCommunity","twitter_misc":{"Written by":"griddb-admin","Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#article","isPartOf":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/"},"author":{"name":"griddb-admin","@id":"https:\/\/griddb.net\/en\/#\/schema\/person\/4fe914ca9576878e82f5e8dd3ba52233"},"headline":"Watching Coastlines Vanish","datePublished":"2026-04-03T18:51:55+00:00","mainEntityOfPage":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/"},"wordCount":1342,"commentCount":0,"publisher":{"@id":"https:\/\/griddb.net\/en\/#organization"},"image":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2026\/04\/coastal_monitoring_featured_image.svg","articleSection":["Blog"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/","url":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/","name":"Watching Coastlines Vanish | GridDB: Open Source Time Series Database for IoT","isPartOf":{"@id":"https:\/\/griddb.net\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#primaryimage"},"image":{"@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#primaryimage"},"thumbnailUrl":"\/wp-content\/uploads\/2026\/04\/coastal_monitoring_featured_image.svg","datePublished":"2026-04-03T18:51:55+00:00","description":"Introduction Global climate change is accelerating sea level rise at an alarming rate\u2014averaging 3.3mm per year due to ocean warming and ice melt\u2014posing","inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/griddb-linux-hte8hndjf8cka8ht.westus-01.azurewebsites.net\/en\/blog\/watching-coastlines-vanish\/#primaryimage","url":"\/wp-content\/uploads\/2026\/04\/coastal_monitoring_featured_image.svg","contentUrl":"\/wp-content\/uploads\/2026\/04\/coastal_monitoring_featured_image.svg","width":680,"height":390},{"@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:\/\/www.griddb.net\/en\/author\/griddb-admin\/"}]}},"_links":{"self":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/55175","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/comments?post=55175"}],"version-history":[{"count":3,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/55175\/revisions"}],"predecessor-version":[{"id":55183,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/posts\/55175\/revisions\/55183"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/media\/55181"}],"wp:attachment":[{"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/media?parent=55175"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/categories?post=55175"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.griddb.net\/en\/wp-json\/wp\/v2\/tags?post=55175"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}