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¶
-
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.0For more information, see go.mod file reference.
-
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,
WithPoolSchemaandWithPoolGraphautomatically set the session context for new connections when they are created. IfWithPoolSchemais 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.