DEV Community

Jbee - codehooks.io
Jbee - codehooks.io

Posted on • Edited on

2

Tutorial part 4: key-value store - data streams

Welcome to this part-4 of the key-value database tutorial for codehooks.io serverless Node.js backend. In this part we'll focus on how to work with multiple key-value pairs in a key-value database.

The Codehooks.io key-value database stores all keys as a sorted string index. This is a very useful feature if you need to store and retrieve multiple values together, as a group or as a segment of key-values.

This article is also avaliable at the official codehooks.io website

IoT device - time series data example

To illustrate this feature we'll create an example use-case for capturing data from multiple IoT devices. In this example, each IoT device sends its location, identification and observations to a specific REST API network endpoint.

For example, a temperature sensor device in the "Alpha region West" reports its value each minute. And a wind force sensor in the "Beta region West" reports its values hourly, and so on.

To ensure that we can access and process the observation data sets effectively, we'll create a key string combination that captures all necessary information in one unique key-value pair.

To illustrate this concept lets imagine a series of IoT device observations as shown in the example below.

'/Alpha/West/density/2023-01-09T10:14:00.495Z'  => '4.4191'
'/Alpha/West/humidity/2023-01-09T17:01:00.821Z' => '0.7539'
'/Alpha/West/temp/2023-01-09T21:15:00.450Z'     => '87.100'
'/Beta/West/wind/2023-01-19T21:57:00.316Z'      => '5.9477'
...
Enter fullscreen mode Exit fullscreen mode

Now that we understand the concept for our IoT database, lets begin the development of an example backend API for IoT sensors.

We'll create a serverless REST API endpoint to receive observations from many IoT devices. The API will store each observation with a logic key that effectively creates a time series database with data points that we can explore and use in our application.

Lets get started with creating the first API to receive data observations from a device.

REST API endpoint to POST a single observation

The REST API route takes in 3 parameters for a given device, region, location and device.
And the POST body must contain the actual device observation data point.
For example:

POST /observation/North/Plaza/humid03 

{"observation": "4.02"}
Enter fullscreen mode Exit fullscreen mode

The route parameters are combined into a unique key with a time stamp which gives a correct time series for the data points. The following table shows some example device observations.

IoT devices time series Data points
/East/BuilingA/temp01/2023-02-22T18:30:14.441Z 21.4
/North/Plaza01/humid3/2023-02-23T05:23:11.306Z 12.5
/East/BuilingB/temp02/2023-02-22T18:32:38.991Z 19.0

The serverless function below implements a REST API endpoint route that can receive data from a device and insert it to the key-value database.

app.post('/observation/:region/:location/:device', async (req, res) => {
    const {region, location, device} = req.params;
    const {observation} = req.body;    
    const key = `/${region}/${location}/${device}/${new Date().toISOString()}`;
    // string key e.g. '/North/Plaza/humid03/2023-02-23T05:23:11.306Z'
    const conn = await Datastore.open();
    const result = await conn.set(key, observation);
    console.log(result)
    res.status(201).end('Data received ok');
})
Enter fullscreen mode Exit fullscreen mode

Test the REST API with curl.

curl -X POST \
  'https://<YOUR_DATABASE_ID>.api.codehooks.io/dev/observation/East/BuilingA/temp01' \
  --header 'x-apikey: <YOUR_API_TOKEN>' \
  --header 'Content-Type: application/json' \
  --data-raw '{
  "observation": "21.4"
}'
Enter fullscreen mode Exit fullscreen mode

Use the CLI command coho info --examples to inspect your project API endpoint and Curl examples.

Inspecting the key-value database with the CLI

The Codehooks CLI can be used to manage the key-value database basic operations, get, set and del. For example, to retrieve all observations for the East locations you can run the following command:

coho get '/East*'
Enter fullscreen mode Exit fullscreen mode

This will list all matching keys in the key-value database as the example output shows below.

{
  key: '/East/BuilingA/temp01/2023-02-23T05:48:19.646Z',
  value: '21.4'
}
{
  key: '/East/BuilingA/temp01/2023-02-23T05:49:06.614Z',
  value: '20.0'
}

2 keys
Enter fullscreen mode Exit fullscreen mode

Endpoint to GET observations subkey

Similiar to the CLI example above, we can use the database API getAll method to retrieve all key-value pairs that match a start segment of a particular key. In this example we are producing CSV data format for easy spreadsheet analysis etc.

app.get('/observations/:prefix', async (req, res) => {
    const conn = await Datastore.open();
    const {prefix} = req.params;
    let count = 0;
    res.set('content-type', 'text/csv');
    res.write('Device, Data\n');
    const stream = conn.getAll(`/${prefix}`);
    stream.on('data', (data) => {
        const outString = `"${data.key}", ${data.val}\n`;
        count++
        res.write(outString);
    }).on('end', () => {
        res.end();        
    })
})
Enter fullscreen mode Exit fullscreen mode

Testing the API with curl again.

curl -X GET \
  'https://<YOUR_DATABASE_ID>.api.codehooks.io/dev/observations/Alpha' \
  --header 'x-apikey: <YOUR_API_TOKEN>' \
Enter fullscreen mode Exit fullscreen mode
Device, Data
"/Alpha/Center/decibel/2023-01-09T11:11:31.218Z", 2.3428
"/Alpha/Center/decibel/2023-01-09T11:12:01.050Z", 6.0632
"/Alpha/Center/decibel/2023-01-09T13:13:30.541Z", 0.7196
"/Alpha/Center/decibel/2023-01-09T15:23:00.589Z", 9.7232
"/Alpha/Center/decibel/2023-01-09T15:34:00.520Z", 5.0089
"/Alpha/Center/decibel/2023-01-09T17:04:00.942Z", 9.1861
Enter fullscreen mode Exit fullscreen mode

Complete source code

The complete source code for our IoT backend application is shown below.

// index.js
import { app, Datastore } from 'codehooks-js' // Standard JS lib for express style code

// list a serie of IoT device observations
app.get('/observations/:prefix', async (req, res) => {
    const conn = await Datastore.open();
    const {prefix} = req.params;
    let count = 0;
    res.set('content-type', 'text/csv');
    res.write('Device, Data\n');
    const stream = conn.getAll(`/${prefix}`);
    stream.on('data', (data) => {
        const outString = `"${data.key}", ${data.val}\n`;
        count++
        res.write(outString);
    }).on('end', () => {
        res.write(`Result: ${count}`);
        res.end();        
    })
})

// register a new IoT device observation
app.post('/observation/:region/:location/:device', async (req, res) => {
    const {region, location, device} = req.params;
    const {observation} = req.body;
    // string key e.g. '/North/Plaza/humid03/2023-02-23T05:23:11.306Z'
    const key = `/${region}/${location}/${device}/${new Date().toISOString()}`;
    const conn = await Datastore.open();
    const result = await conn.set(key, observation);
    console.log(result)
    res.status(201).end('Data received ok');
})

export default app.init(); // Bind functions to the serverless cloud
Enter fullscreen mode Exit fullscreen mode

This part-4 of the key-value store tutorial has shown how you can combine smart keys with the database streaming capabilities to create kind of IoT time series database with codehooks.io.

In our next tutorial [Part-5: Managing data with TTL options(https://codehooks.io/docs/tutorials/key-val-store/part-5-managing-data-with-ttl-options), we'll explore how you can use the time-to-live (TTL) feature to delete old data in the key-value database.

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

While many AI coding tools operate as simple command-response systems, Qodo Gen 1.0 represents the next generation: autonomous, multi-step problem-solving agents that work alongside you.

Read full post

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More