How to Use the InfluxDB with Golang on Ubuntu 20.04

Updated on January 7, 2022
How to Use the InfluxDB with Golang on Ubuntu 20.04 header image

Introduction

InfluxDB is an open-source time-series database specifically suitable for IoT projects, cloud-native services, and more. The package is written in the Golang programming language. You can use it for data exploration, data visualization, and to run dashboard applications.

While InfluxDB comes with great tools for storing, querying, and processing data, you can still use its API libraries inside your Golang project. This enhances flexibility when working with the time series data since you can pass it through custom functions that may not be available in the InfluxDB codebase.

In this guide, you'll implement the InfluxDB database functions with Golang on your Ubuntu 20.04 server.

Prerequisites

To proceed with this guide, make sure you have the following:

1. Create an InfluxDB Database

In this tutorial, you'll set up an InfluxDB database and insert some time-series data for testing purposes. Later, you'll query your InfluxDB server via a Golang script to retrieve or insert points to the database.

Connect to your server to complete the following steps:

  1. Log in to the InfluxDB server. Replace admin with the name of your InfluxDB super-user account. Pass the -password '' option to allow the following influx command to prompt you for a password.

     $ influx -username 'admin' -password ''
  2. Key in your password and press Enter to proceed. Next, execute the following statement to create a sample_db database.

     > CREATE DATABASE sample_db
  3. Switch to the new sample_db database.

     > USE sample_db
  4. Insert the following points into your sample_db database under the power_usage measurement. In this application, you're tracking the power loads for users in different homes where a solar system has been installed. In this step, you'll enter the data manually, but this data may originate from IoT devices installed in all homes requiring measurement tracking in a production environment.

     > INSERT power_usage,client_id=100731,location=BRANSON current_load_in_amperes=0.2
     > INSERT power_usage,client_id=800478,location=MIAMI current_load_in_amperes=0.1
     > INSERT power_usage,client_id=907854,location=CHICAGO current_load_in_amperes=0.4
     > INSERT power_usage,client_id=532681,location=CHARLESTON current_load_in_amperes=0.1
  5. Query the power_usage measurement to make sure the data is in place.

     > SELECT "client_id", "location", "current_load_in_amperes" FROM power_usage
  6. You should get the following output showing time-stamped data as you entered it in the sample_db database.

     time                client_id location   current_load_in_amperes
     ----                --------- --------   -----------------------
     1638542140183389389 100731    BRANSON    0.2
     1638542147803130270 800478    MIAMI      0.1
     1638542155163864457 907854    CHICAGO    0.4
     1638542162283179983 532681    CHARLESTON 0.1
  7. Log out from the InfluxDB server.

     > QUIT

2. Create a main.go File

In this application, you'll create a main.go file. This runs the main(...) function that fires when you start the application.

  1. Separate your source code files from the rest of the Linux files by creating a new project directory.

     $ mkdir project
  2. Next, navigate to the project directory.

     $ cd project
  3. Then, use nano to open a new main.go file.

     $ nano main.go
  4. Enter the following information into the main.go file.

     package main
    
     import (
     "net/http"
     "encoding/json"
     "fmt"
     )    
    
     func main() {
         http.HandleFunc("/power-consumptions", httpHandler)            
         http.ListenAndServe(":8080", nil)
     }
    
     func httpHandler(w http.ResponseWriter, req *http.Request) { 
    
         var err error
    
         resp := map[string]interface{}{}
    
         if req.Method == "POST" {
    
             params := map[string]interface{}{}
    
             err = json.NewDecoder(req.Body).Decode(&params)
    
             if err != nil {
                 fmt.Fprintf(w, err.Error()) 
             }
    
             resp, err = createPoint(params)
         } 
    
         if req.Method == "GET" {
    
             resp, err = getPoints()
    
         }
    
         enc := json.NewEncoder(w)
         enc.SetIndent("", "  ") 
    
         if err != nil {
    
             fmt.Println(err.Error())
    
         } else {
    
            if err := enc.Encode(resp); err != nil {
              fmt.Println(err.Error())
            } 
    
         }
    
     }
  5. Save and close the main.go file when you're through with editing.

  6. In the above file, you've created a main() function to listen for incoming HTTP requests on port 8080. You've then redirected the request to the httpHandler() function to determine the HTTP req.Method. For POST requests, you're calling a createPoint(params) function, which you'll create in a new file later. This function accepts the JSON payload as an argument for the point that you want to create to the database.

  7. Next, you're redirecting GET requests to the getPoints() function, which retrieves data from the database and returns a map.

3. Create an influxdb.go File

You'll create a file to interact with your InfluxDB server in this step. This file contains two functions. You'll use the createPoint() function to enter new points into the database and the getPoints() function to retrieve entries from your power_usage measurement.

  1. Use nano to create a new influxdb.go file.

     $ nano influxdb.go
  2. Next, enter the following information into the influxdb.go file. Replace const USERNAME and const PASSWORD with the correct authentication credentials for your InfluxDB server.

     package main
    
     import (    
         "github.com/influxdata/influxdb1-client/v2"
         "time"
         "errors"
     )
    
     const (
         USERNAME string = "admin"
         PASSWORD string = "EXAMPLE_PASSWORD"
         DATABASE string = "sample_db"
     )
    
    
     func createPoint(params map[string]interface{}) (map[string]interface{}, error) { 
    
         influxClient, err := client.NewHTTPClient(client.HTTPConfig{
                   Addr: "http://localhost:8086",
                       Username: USERNAME,    
                   Password: PASSWORD,
                   })
    
         if err != nil {
             return nil, err
         }
    
         bp, err := client.NewBatchPoints(client.BatchPointsConfig{    
         Database: DATABASE,
     })
    
         if err != nil {
             return nil, err
         } 
    
         clientId := params["client_id"].(string) 
         location := params["location"].(string)
         currentLoadInAmperes := params["current_load_in_amperes"]
    
         pt, err := client.NewPoint("power_usage", map[string]string{"client_id": clientId, "location": location},
                          map[string]interface{}{"current_load_in_amperes": currentLoadInAmperes},
                          time.Now())
    
         if err != nil {
             return nil, err
         } 
    
         bp.AddPoint(pt)
    
         err =  influxClient.Write(bp)         
    
         if err != nil {
             return nil, err           
         }
    
         resp := map[string]interface{}{"data" : "Success"}
    
         return resp, nil            
    
     }
    
     func getPoints() (map[string]interface{}, error) { 
    
         influxClient, err := client.NewHTTPClient(client.HTTPConfig{
                   Addr: "http://localhost:8086",
                       Username: USERNAME,    
                   Password: PASSWORD,
                   })
    
         if err != nil {
             return nil, err
         }
    
         queryString := "SELECT client_id, location, current_load_in_amperes FROM power_usage"
    
         q := client.NewQuery(queryString, DATABASE, "ns")
    
         response, err := influxClient.Query(q)
    
         if err != nil {
             return nil, err
         }
    
         err = response.Error()
    
     if err != nil {
    
              return nil, errors.New("Empty record set")
    
     } else {
    
             res := response.Results
    
             if (len(res) == 0) {
                return nil, err
             }
    
             columns := response.Results[0].Series[0].Columns
             points  := response.Results[0].Series[0].Values              
    
             data := []map[string]interface{}{}                               
    
             for i := 0; i <= len(points) - 1 ; i++ {   
    
                 record  := map[string]interface{}{}                  
    
                 for j := 0; j <= len(columns) - 1; j++ {                   
                     record[string(columns[j])] = points[i][j]                   
                 }
    
                 data = append(data, record)   
    
             }
    
             resp := map[string]interface{}{"data" : data}
    
             return resp, nil    
         }
     }
  3. Save and close the influxdb.go file when you're through with editing.

  4. In the above file, you have two functions. You're using the createPoint function to connect and create a point in your InfluxDB database using the payload passed from the main.go file. Then, you're using the getPoints() function to connect and retrieve points from the power_usage measurement. In each case, you're returning a map to the calling function or an error, if any.

4. Test the Golang InfluxDb Application.

You now have a main.go file that listens for incoming requests and an influxdb.go that creates and retrieves points from your InfluxDB database. Your application is now ready for testing.

  1. Download the InfluxDB packages that you've used in the project.

     $ go get github.com/influxdata/influxdb1-client/v2
  2. Next, run the application. A web server should now listen on port 8080. Don't enter any other command in this SSH session.

     $ go run ./
  3. SSH to your server on another terminal window and execute the following curl POST command to create a new entry into your InfluxDB database.

     $ curl -i -X POST localhost:8080/power-consumptions -H "Content-Type: application/json" -d '{"client_id": "656565", "location": "NAIROBI", "current_load_in_amperes": 0.3}'
  4. Confirm the following output. This means you've successfully created a new point into the database.

     {
         "data": "Success"
     }
  5. Then, issue the following GET command to retrieve points from the database.

     $ curl -i -X GET localhost:8080/power-consumptions
  6. You should get the following output with all points, including the latest NAIROBI entry you've created with the curl command.

     {
       "data": [
         {
           "client_id": "100731",
           "current_load_in_amperes": 0.2,
           "location": "BRANSON",
           "time": 1638542140183389389
         },
         {
           "client_id": "800478",
           "current_load_in_amperes": 0.1,
           "location": "MIAMI",
           "time": 1638542147803130270
         },
         {
           "client_id": "907854",
           "current_load_in_amperes": 0.4,
           "location": "CHICAGO",
           "time": 1638542155163864457
         },
         {
           "client_id": "532681",
           "current_load_in_amperes": 0.1,
           "location": "CHARLESTON",
           "time": 1638542162283179983
         },
         {
           "client_id": "656565",
           "current_load_in_amperes": 0.3,
           "location": "NAIROBI",
           "time": 1638542346252178453
         }
       ]
     }
  7. Your application is working as expected.

Conclusion

In this guide, you've implemented InfluxDB database functions with Golang on your Ubuntu 20.04 server to create and retrieve points using a custom JSON API.

Follow the links below to read more Golang tutorials: