Skip to content
Developer Edition runs on one host and does not require a product license file. Need multi-host deployment or performance testing at scale? Explore Enterprise Edition

Go SDK guide

This topic introduces how to set up the Go SDK to connect to NebulaGraph Database Developer Edition and perform simple queries.

Prerequisites

A NebulaGraph Database Developer Edition service group is running. For more information, see Getting started.

Steps

  1. Modify the Go module dependencies to use the local version of the Go SDK. Example:

    workspace=/app/myapp
    
    # In your project, run go mod edit
    cd ${workspace}
    go get github.com/vesoft-inc/nebula-go/v5@5.3.0
    

    For more information, see go.mod file reference.

  2. Use the SDK to connect to NebulaGraph Database Developer Edition and perform queries as follows:

    Note

    Apart from specifying the username and password when connecting to NebulaGraph Database Developer Edition, you can also enable the sessionless mode, which allows you to not provide authentication information. For more information, see Sessionless mode.

    package main
    
    import (
     "fmt"
    
     nebula "github.com/vesoft-inc/nebula-go/v5"
    )
    
    const (
     address  = "<host>:<port>"
     username = "<username>"
     password = "<password>"
    )
    
    // Initialize logger
    var log = nebula.DefaultLogger
    
    func basicClient() {
     client, err := nebula.NewNebulaClient(address, username, password)
     if err != nil {
      log.Error(err.Error())
      return
     }
     resp, err := client.Execute("return 1 as a")
     if err != nil {
      log.Error(err.Error())
      return
     }
     log.Info(fmt.Sprintf("columns: %v", resp.Columns()))
     for resp.HasNext() {
      row, err := resp.Next()
      if err != nil {
       log.Error(err.Error())
       return
      }
      v1, err := row.GetValueByIndex(0)
      if err != nil {
       log.Error(err.Error())
       return
      }
      log.Info(v1.String())
      v2, err := row.GetValueByName("a")
      if err != nil {
       log.Error(err.Error())
       return
      }
      log.Info(v2.String())
     }
    }
    
    func basicPool() {
     pool, err := nebula.NewNebulaPool(address, username, password)
     if err != nil {
      log.Error(err.Error())
      return
     }
     client, err := pool.GetClient()
     if err != nil {
      log.Error(err.Error())
      return
     }
     resp, err := client.Execute("return 1 as a")
     if err != nil {
      log.Error(err.Error())
      return
     }
     log.Info(fmt.Sprintf("columns: %v", resp.Columns()))
     for resp.HasNext() {
      row, err := resp.Next()
      if err != nil {
       log.Error(err.Error())
       return
      }
      v1, err := row.GetValueByIndex(0)
      if err != nil {
       log.Error(err.Error())
       return
      }
      log.Info(v1.String())
      v2, err := row.GetValueByName("a")
      if err != nil {
       log.Error(err.Error())
       return
      }
      log.Info(v2.String())
     }
    }
    
    func main() {
     basicClient()
     basicPool()
    }
    

    If the target graph is not in the default schema (/default_schema), you can specify the schema in one of the following ways:

    // Method 1: for a client from NewNebulaClient, set schema and graph explicitly
    _, err = client.Execute("SESSION SET SCHEMA /my_schema")
    if err != nil {
     log.Error(err.Error())
     return
    }
    
    _, err = client.Execute("USE my_graph")
    if err != nil {
     log.Error(err.Error())
     return
    }
    
    resp, err = client.Execute("MATCH (v) RETURN v LIMIT 10")
    if err != nil {
     log.Error(err.Error())
     return
    }
    
    // Method 2: for NewNebulaPool, set schema and graph during pool initialization
    pool, err := nebula.NewNebulaPool(
     address,
     username,
     password,
     nebula.WithPoolSchema("/my_schema"),
     nebula.WithPoolGraph("my_graph"),
    )
    if err != nil {
     log.Error(err.Error())
     return
    }
    defer pool.Close()
    
    client2, err := pool.GetClient()
    if err != nil {
     log.Error(err.Error())
     return
    }
    defer pool.PutClient(client2)
    
    resp, err = client2.Execute("MATCH (v) RETURN v LIMIT 10")
    if err != nil {
     log.Error(err.Error())
     return
    }
    

    When using a connection pool, WithPoolSchema and WithPoolGraph automatically set the session context for new connections when they are created. If WithPoolSchema is omitted, new sessions use the default schema (/default_schema).

    For more information, see SESSION SET SCHEMA and USE clause.

    Replace <host>, <port>, <username>, and <password> with the actual NebulaGraph Database Developer Edition connection information.

Best practices

When processing query results, you can use either of the following methods to store the result values:

  • Method one: declare a struct variable inside the loop

      resp, err = client.Execute(query)
      if err != nil {
          log.Error(fmt.Sprintf("Failed to execute query: %v", err))
          return
      }
      for resp.HasNext() {
          var p Person
          if err := resp.Scan(&p.id, &p.birthday, &p.firstName); err != nil {
              log.Error(fmt.Sprintf("Failed to scan row: %v", err))
              return
          }
          if p.id.Valid && p.birthday.Valid && p.firstName.Valid {
              fmt.Printf("id: %d, ", p.id.Data)
              fmt.Printf("birthday: %d-%d-%d, ", p.birthday.Data.GetYear(),
                  p.birthday.Data.GetMonth(), p.birthday.Data.GetDay())
              fmt.Printf("first name: %s\n", p.firstName.Data)
          }
      }
    
  • Method two: declare a struct variable outside the loop

      resp, err = client.Execute(query)
      if err != nil {
          log.Error(fmt.Sprintf("Failed to execute query: %v", err))
          return
      }
      var p Person
      for resp.HasNext() {
          if err := resp.Scan(&p.id, &p.birthday, &p.firstName); err != nil {
              log.Error(fmt.Sprintf("Failed to scan row: %v", err))
              return
          }
          if p.id.Valid && p.birthday.Valid && p.firstName.Valid {
              fmt.Printf("id: %d, ", p.id.Data)
              fmt.Printf("birthday: %d-%d-%d, ", p.birthday.Data.GetYear(),
                  p.birthday.Data.GetMonth(), p.birthday.Data.GetDay())
              fmt.Printf("first name: %s\n", p.firstName.Data)
          }
      }
    

In the above two methods, the query result is scanned into the Person struct, which is defined as follows:

type Person struct {
    id        nebula.NullInt64
    birthday  nebula.NullDate
    firstName nebula.NullString
}

In method one, the Person struct is declared inside the loop, so a new instance of p is created for each iteration. In method two, it is declared outside the loop, so the same instance of p is reused for each iteration. Both methods are valid, but method two is more efficient in terms of memory usage and performance, especially when processing large result sets.

More information