#前面已經分享過以 HTTP API 或 JavaScript driver 開發 Neo4j 前端應用,今天我們就來看後端應用囉,這篇文章會以 Golang 語言為參考。
目前(2020/10) Neo4j 官方支援的程式語言有 Java、 .NET、JavaScript、Python、Go,針對 Java 還有額外支援框架 Spring、Neo4j-OGM。
其他語言如 Ruby、PHP、Erlang/Elixir、Perl、C/C++、Clojure、Haskell、R 則都是 Neo4j 社區中的開發者們所貢獻,但也都有收錄在官方教學

安裝 Golang driver for Neo4j

使用 go get 或 GO Module 管理 package,建議後者。

go get github.com/neo4j/neo4j-go-driver/neo4j
go mod init github.com/eggttball/go-neo4j
go mod edit -require github.com/neo4j/neo4j-go-driver@v1.8.3

Import neo4j driver

import "github.com/neo4j/neo4j-go-driver/neo4j"

宣告 Neo4j driver 物件

driver
session

create driver and session

driver, err := neo4j.NewDriver("bolt://localhost:7687", neo4j.BasicAuth("neo4j", password, ""), func(c *neo4j.Config) {
    c.Encrypted = encrypted
})
if err != nil {
    return "", err
}
defer driver.Close()

session, err := driver.Session(neo4j.AccessModeWrite)
if err != nil {
    return "", err
}
defer session.Close()

這邊指定的 Access Mode Read/Write 有助於在連線因果叢集時,讓叢集決定要將 Cypher 查詢指派給 Core server 還是 Replica server,正確的設定 Access Mode 將有助於資料庫的效能大幅提升。
不過在 Session 初始化時的 Access Mode 只會影響自動交易,如果是手動交易,Access Mode 最終還是取決於 Session.WriteTransaction 或是 Session.ReadTransaction

自動 Commit 的交易

Session.Run

Result.Consume 會一次讀取所有的回傳資料並回傳 Summary

result, err := session.Run("CREATE (a:Person {name: $name})", map[string]interface{}{"name":
name})
if err != nil {
    return err
}

if _, err = result.Consume(); err != nil {
    return err
}

手動交易

greeting, err := session.WriteTransaction(func(transaction neo4j.Transaction) (interface{}, error) {
    result, err := transaction.Run(
        "CREATE (a:Greeting) SET a.message = $message RETURN a.message + ', from node ' + id(a)",
        map[string]interface{}{"message": "hello, world"})
    if err != nil {
        return nil, err
    }
    if result.Next() {
        return result.Record().GetByIndex(0), nil
    }
    return nil, result.Err()
})

這邊用到了 Result.Next() 來確認是否有回傳結果,以及 Result.Record() 來取得每一筆資料
如果預期回傳的資料有多筆,可以這樣寫。

for result.Next() {
    record = result.Record();
    if value, ok := record.Get('field_name'); ok {
        // a value with alias field_name was found
        // process value
    }
}

以上也刻意示範了 Get by index 和 Get by field name 的選擇作法

Cypher 與 Golang driver 的資料型別對應

從資料庫取得的結果都會是 interface{} 型別,在程式碼中的操作很不便,但我們可以把它 UnBoxing 成真正的物件型別,列表如下

Cypher Type Driver Type
null nil
List []interface{}
Map map[string]interface{}
Boolean bool
Integer int64
Float float
String string
ByteArray []byte
Node neo4j.Node
Relationship neo4j.Relationship
Path neo4j.Path
Point neo4j.Point
Date neo4j.Date
Time neo4j.OffsetTime
LocalTime neo4j.LocalTime
DateTime time.Time
LocalDateTime neo4j.LocalDateTime
Duration neo4j.Duration

例如

value, ok := record.Get('birthday').(neo4j.Date)

連線因果叢集

如果資料庫是採用因果叢集架構,只需要將協定改成 bolt+routing 中可,後面接的機器位址則必須是任一台 Core Server。

if driver, err = neo4j.NewDriver("bolt+routing://localhost:7687", neo4j.BasicAuth("username", "password", "")); err != nil {
    return err
}

資考資源:

https://github.com/neo4j/neo4j-go-driver
https://neo4j.com/docs/pdf/neo4j-driver-manual-1.7-go.pdf
https://godoc.org/github.com/neo4j/neo4j-go-driver/neo4j