mcpField
N
neo4j-driver-go-skill

neo4j-driver-go-skill

github.com/neo4j-contrib開発118780 回インストール1 週間前に更新
リポジトリ

neo4j-driver-go-skill について

Go アプリケーションから Neo4j に接続する開発者向けのスキルガイドです。ドライバー設定、クエリとトランザクション、結果処理、エラー対応、性能と安全性の実践方法を扱います。

主な機能

  1. 01Neo4j Go Driver v6 の設定
  2. 02クエリとトランザクション API の選択
  3. 03結果型とエラーの処理
  4. 04接続、セッション、コンテキストの管理
  5. 05バッチ処理とパラメーター化クエリ

活用シーン

  1. 01Go アプリケーションから Neo4j へ接続
  2. 02接続や結果反復エラーの調査
  3. 03大きな結果セットでのストリーミング選択
  4. 04再試行を考慮したトランザクションの実装

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/neo4j-contrib/neo4j-skills --skill neo4j-driver-go-skill

インストール後、Claude Code で/neo4j-driver-go-skillを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
references/
advanced-config.md
repository-pattern.md

詳細

使用する場面

  • Neo4j に接続する Go コードを書く場合
  • neo4j.NewDriver()、ExecuteQuery()、またはセッション/トランザクションのパターンを設定する場合
  • 接続エラー、結果の反復処理、型アサーション、因果整合性をデバッグする場合

使用しない場面

  • Cypher の作成/最適化 → neo4j-cypher-skill
  • v5→v6 の移行手順 → neo4j-migration-skill

インストール

go get github.com/neo4j/neo4j-go-driver/v6

インポート:github.com/neo4j/neo4j-go-driver/v6/neo4j

v5→v6 の名称変更(非推奨のエイリアスでも引き続きコンパイルできますが、v7 までに削除してください):

v5v6
neo4j.NewDriverWithContext(...)neo4j.NewDriver(...)
neo4j.DriverWithContextneo4j.Driver

環境変数

import "os"

uri      := getEnv("NEO4J_URI",      "neo4j://localhost:7687")
user     := getEnv("NEO4J_USERNAME", "neo4j")
password := getEnv("NEO4J_PASSWORD", "")
database := getEnv("NEO4J_DATABASE", "neo4j")

func getEnv(key, fallback string) string {
    if v := os.Getenv(key); v != "" { return v }
    return fallback
}

開発環境で .env を読み込むには godotenv を使用します:godotenv.Load()。.env は .gitignore に追加してください。


ドライバーのライフサイクル

アプリケーションごとに Driver を 1 つ使用します。ゴルーチンセーフで、コネクションプールを使用し、作成コストが高いためです。

func NewNeo4jDriver(uri, user, password string) (neo4j.Driver, error) {
    driver, err := neo4j.NewDriver(
        uri, // "neo4j+s://xxx.databases.neo4j.io" for Aura
        neo4j.BasicAuth(user, password, ""),
    )
    if err != nil {
        return nil, fmt.Errorf("create driver: %w", err)
    }
    ctx := context.Background()
    if err := driver.VerifyConnectivity(ctx); err != nil {
        driver.Close(ctx)
        return nil, fmt.Errorf("verify connectivity: %w", err)
    }
    return driver, nil
}

// In main / app teardown:
defer driver.Close(ctx)

❌ リクエストごとにドライバーを作成しないでください。起動時に一度作成し、ゴルーチン間で共有します。

URI スキーム:neo4j+s://(Aura/TLS+ルーティング)、neo4j://(平文+ルーティング)、bolt+s://(TLS+単一接続)、bolt://(平文+単一接続)。


適切な API の選択

API使用する場面自動再試行遅延結果
neo4j.ExecuteQuery()ほとんどのクエリ — シンプルなデフォルト✅❌ 即時
session.ExecuteRead/Write()大きな結果セット/ストリーミング✅✅
session.BeginTransaction()複数の関数にまたがる処理/外部システムとの連携❌✅
session.Run()CALL IN TRANSACTIONS/自動コミットのみ❌✅

CALL { … } IN TRANSACTIONS と USING PERIODIC COMMIT は独自にトランザクションを管理します。session.Run() を使用してください。管理対象トランザクション内では失敗します。


ExecuteQuery(推奨デフォルト)

セッション、トランザクション、再試行、ブックマークを自動的に管理します。

result, err := neo4j.ExecuteQuery(ctx, driver,
    `MATCH (p:Person {name: $name})-[:KNOWS]->(friend)
     RETURN friend.name AS name`,
    map[string]any{"name": "Alice"},
    neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("neo4j"),       // always specify
    neo4j.ExecuteQueryWithReadersRouting(),         // for read queries
)
if err != nil {
    return fmt.Errorf("query people: %w", err)
}

for _, record := range result.Records {
    name, _ := record.Get("name")
    fmt.Println(name)
}
fmt.Println(result.Summary.Counters().NodesCreated())

主なオプション:

neo4j.ExecuteQueryWithDatabase("mydb")          // required for performance
neo4j.ExecuteQueryWithReadersRouting()           // route reads to replicas
neo4j.ExecuteQueryWithImpersonatedUser("jane")  // impersonate
neo4j.ExecuteQueryWithoutBookmarkManager()       // opt out of causal consistency

❌ ユーザー入力をクエリ文字列に連結しないでください。必ず map[string]any のパラメーターを使用してください。

構造体パラメーター(v6.2.0 以降、オブジェクトマッピングのプレビュー):params 内の構造体(またはポインター)は Cypher のマップとして送信されます。同じルールが Session.Run、ManagedTransaction.Run、ExplicitTransaction.Run に適用されます:

type Person struct {
    Name     string `neo4j:"name"`
    Age      int    `neo4j:"age,omitempty"`  // zero value dropped
    Internal string `neo4j:"-"`              // never sent
}
_, err := neo4j.ExecuteQuery(ctx, driver,
    "MERGE (p:Person {name: $person.name}) SET p += $person",
    map[string]any{"person": Person{Name: "Alice", Age: 30}},
    neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("neo4j"),
)

管理対象トランザクション(セッションベース)

遅延ストリーミング(大きな結果セット)やコールバックレベルの制御が必要な場合に使用します。

session := driver.NewSession(ctx, neo4j.SessionConfig{
    DatabaseName: "neo4j", // always specify
    AccessMode:   neo4j.AccessModeRead,
})
defer session.Close(ctx)

result, err := session.ExecuteRead(ctx,
    func(tx neo4j.ManagedTransaction) (any, error) {
        res, err := tx.Run(ctx,
            `MATCH (p:Person) RETURN p.name AS name LIMIT $limit`,
            map[string]any{"limit": 100},
        )
        if err != nil {
            return nil, err
        }
        var names []string
        for res.Next(ctx) { // lazy — don't Collect() on large sets
            name, _ := res.Record().Get("name")
            names = append(names, name.(string))
        }
        return names, res.Err()
    },
)

❌ コールバック内で副作用を発生させないでください。一時的な障害時に再試行されます。 ExecuteRead → レプリカ。ExecuteWrite → クラスターリーダー。


明示的なトランザクション

トランザクション処理が複数の関数にまたがる場合や、外部との連携が必要な場合に使用します。

session := driver.NewSession(ctx, neo4j.SessionConfig{DatabaseName: "neo4j"})
defer session.Close(ctx)

tx, err := session.BeginTransaction(ctx)
if err != nil {
    return err
}
if err := doPartA(ctx, tx); err != nil {
    tx.Rollback(ctx)
    return err
}
if err := doPartB(ctx, tx); err != nil {
    tx.Rollback(ctx)
    return err
}
return tx.Commit(ctx)

❌ 自動再試行されません。呼び出し元が再試行を処理します。明示的な制御が必要でない限り、管理対象トランザクションを優先してください。


エラー処理

result, err := neo4j.ExecuteQuery(...)
if err != nil {
    var neo4jErr *neo4j.Neo4jError
    if errors.As(err, &neo4jErr) {
        slog.Error("database error", "code", neo4jErr.Code, "msg", neo4jErr.Msg)
    }
    var connErr *neo4j.ConnectivityError
    if errors.As(err, &connErr) {
        slog.Error("connectivity error", "err", connErr)
    }
    return fmt.Errorf("execute query: %w", err)
}

ヘルパー:

neo4j.IsNeo4jError(err)                // server-side Cypher/database error
neo4j.IsTransactionExecutionLimit(err) // managed tx retries exhausted

管理対象トランザクションのコールバックでは、エラーを返すと、一時的なエラーの場合にドライバーが再試行します。 起動時に ConnectivityError が発生する場合は、URI スキーム、認証情報、ファイアウォールを確認してください。


データ型

CypherGo
Integerint64
Floatfloat64
Stringstring
Booleanbool
List[]any
Mapmap[string]any
Nodeneo4j.Node
Relationshipneo4j.Relationship
Pathneo4j.Path
Dateneo4j.Date
DateTimeneo4j.Time
Durationneo4j.Duration
UUIDneo4j.UUID(= dbtype.UUID、[16]byte RFC 9562)— v6.2.0 以降、Bolt 6.1。dbtype.ParseUUID(s) で解析し、.String() で文字列に変換
nullnil
// Typed extraction (v6+, preferred):
neo4j.GetRecordValue[string](record, "name")

// Manual extraction:
rawAge, ok := record.Get("age")
if !ok { return errors.New("missing 'age' field") }
age := rawAge.(int64) // Neo4j integers → int64

// Node access:
rawNode, _ := record.Get("p")
node := rawNode.(neo4j.Node)
name := node.Props["name"].(string)
labels := node.Labels // []string

❌ 型アサーションの前に、必ず record.Get() の ok を確認してください。キーがない場合、パニックが発生します。 ❌ 遅延評価される for res.Next(ctx) ループの後は、必ず res.Err() を確認してください。


主なパターン

Context — 常に伝播させる
ctx, cancel := context.WithTimeout(parentCtx, 5*time.Second)
defer cancel()
// pass ctx to all driver calls

context.Background() には期限がないため、遅いクエリが無期限にブロックします。

書き込みのバッチ処理
// Bad: one transaction per record
for _, item := range items {
    neo4j.ExecuteQuery(ctx, driver, writeQuery, item, ...)
}

// Good: UNWIND batch in one transaction
neo4j.ExecuteQuery(ctx, driver,
    `UNWIND $items AS item
     MERGE (n:Node {id: item.id})
     SET n += item`,
    map[string]any{"items": items},
    neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("neo4j"),
)
汎用ヘルパー(v6+)

手動で型アサーションを行うより、型安全なヘルパーを優先してください。

// GetRecordValue[T] — extract + cast in one call
name, isNil, err := neo4j.GetRecordValue[string](record, "name")
// isNil=true when OPTIONAL MATCH returned null; err != nil when key absent or wrong type

// CollectTWithContext — map all records to a slice
people, err := neo4j.CollectTWithContext(ctx, result, func(record *neo4j.Record) (Person, error) {
    name, _, err := neo4j.GetRecordValue[string](record, "name")
    age, _, _   := neo4j.GetRecordValue[int64](record, "age")
    return Person{Name: name, Age: int(age)}, err
})

// SingleTWithContext — expect exactly one record (error if 0 or 2+)
person, err := neo4j.SingleTWithContext(ctx, result, func(record *neo4j.Record) (Person, error) {
    name, _, _ := neo4j.GetRecordValue[string](record, "name")
    return Person{Name: name}, nil
})

// GetProperty — typed property from Node or Relationship
node, _, _ := neo4j.GetRecordValue[neo4j.Node](record, "p")
nameVal, err := neo4j.GetProperty[string](node, "name")

結果のマッピング[v6.3.0+、オブジェクトマッピングプレビュー]— レコードを neo4j タグ付きの構造体にマッピングします(構造体パラメーターと同じタグを使用します)。

type Person struct {
    Name string `neo4j:"name"`
    Age  int    `neo4j:"age"`   // INTEGER converted; lossy conversion → error, not truncation
}

// EagerResult from ExecuteQuery
res, err := neo4j.ExecuteQuery(ctx, driver,
    "MATCH (p:Person) RETURN p.name AS name, p.age AS age LIMIT 25",
    nil, neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase("neo4j"))
people, err := neo4j.CollectRecordsAs[Person](res.Records)

// Streaming Result inside a transaction
all, err := neo4j.CollectAs[Person](ctx, result)      // all records
person, err := neo4j.SingleAs[Person](ctx, result)    // exactly one record
p, err := neo4j.As[Person](record)                    // single record

マッピングのルール:ノード、リレーションシップ、またはマップを含む列が1つの場合、そのプロパティがフィールドにマッピングされます。それ以外の場合は、列名でマッピングされます。欠損値/null はゼロ値になり、余分な列は無視されます。

空間型
// 2D Cartesian (SRID 7203), 3D Cartesian (SRID 9157)
pt2d := neo4j.Point2D{X: 1.23, Y: 4.56, SpatialRefId: 7203}
pt3d := neo4j.Point3D{X: 1.23, Y: 4.56, Z: 7.89, SpatialRefId: 9157}

// 2D WGS-84 (SRID 4326), 3D WGS-84 (SRID 4979)
london := neo4j.Point2D{X: -0.118092, Y: 51.509865, SpatialRefId: 4326}
shard  := neo4j.Point3D{X: -0.0865, Y: 51.5045, Z: 310, SpatialRefId: 4979}

// Pass as parameter
result, err := neo4j.ExecuteQuery(ctx, driver,
    "CREATE (p:Place {location: $loc})",
    map[string]any{"loc": london},
    neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("neo4j"),
)

// Read from result — assert to Point2D or Point3D
raw, _ := record.Get("location")
if p2d, ok := raw.(neo4j.Point2D); ok {
    fmt.Printf("lon=%f lat=%f srid=%d\n", p2d.X, p2d.Y, p2d.SpatialRefId)
}

// Distance (same SRID only)
result, _ = neo4j.ExecuteQuery(ctx, driver,
    "RETURN point.distance($p1, $p2) AS distance",
    map[string]any{"p1": pt2d, "p2": neo4j.Point2D{X: 10, Y: 10, SpatialRefId: 7203}},
    neo4j.EagerResultTransformer, neo4j.ExecuteQueryWithDatabase("neo4j"),
)
dist, _ := result.Records[0].Get("distance")
fmt.Println(dist.(float64))
データベースを必ず指定する
neo4j.ExecuteQueryWithDatabase("neo4j")    // in ExecuteQuery
neo4j.SessionConfig{DatabaseName: "neo4j"} // in sessions

省略すると、ホームデータベースを特定するために、呼び出しごとにネットワークのラウンドトリップが発生します。

因果的一貫性

ExecuteQuery はブックマークを自動的に管理するため、逐次呼び出しでは何もする必要はありません。 セッションをまたぐ場合(並列ワーカー):ブックマークを明示的に組み合わせてください。references/repository-pattern.md を参照してください。


よくあるエラー

エラー/症状原因対処法
起動時に ConnectivityError が発生するURI の誤り/TLS の不一致/ファイアウォールスキーム(Aura の場合は neo4j+s://)、認証情報、ポート 7687 を確認します
実行中に ConnectivityError が発生するプールの枯渇MaxConnectionPoolSize を増やし、セッションの閉じ忘れがないか確認します
型アサーションでパニックが発生するrecord.Get() が nil または誤った型を返したneo4j.GetRecordValue[T]() を使用するか、先に ok を確認します
ループ後に res.Err() が nil 以外になるストリーム中のネットワークエラーエラーを処理し、トランザクションを再実行します
コールバックが予期せず再試行される管理対象トランザクション内で副作用が発生している副作用をコールバックの外に移します
コンテキストの期限を超過したコンテキストにタイムアウトが設定されていないcontext.WithTimeout を使用します
クエリが正しく見えるのに結果が 0 件DatabaseName が間違っている設定で必ず DatabaseName を指定します
CALL IN TRANSACTIONS が失敗する管理対象トランザクション内で実行しているsession.Run()(自動コミット)を使用します

参考資料

必要に応じて読み込んでください。

  • references/advanced-config.md — 接続プールの調整、カスタムアドレスリゾルバー、通知設定、Bolt のログ記録、認証オプション、URI スキーム一覧、非推奨の結果サマリーアクセサー(Profile() → QueryProfile())
  • references/repository-pattern.md — リポジトリーラッパーパターン、ブックマークを使用したセッションをまたぐ因果的一貫性

WebFetch

必要な情報URL
Go ドライバーマニュアルhttps://neo4j.com/docs/go-manual/current/
API リファレンスhttps://pkg.go.dev/github.com/neo4j/neo4j-go-driver/v6/neo4j

チェックリスト

  • 起動時にドライバーを1つ作成し、ゴルーチン間で共有する。defer driver.Close(ctx) を使用する
  • 起動時に driver.VerifyConnectivity(ctx) を呼び出す
  • すべての SessionConfig/ExecuteQueryWithDatabase で DatabaseName を設定する
  • 本番クエリでは context.WithTimeout を使用する
  • パラメーターには map[string]any を使用し、文字列補間を行わない
  • 読み取り専用の ExecuteQuery 呼び出しでは ExecuteQueryWithReadersRouting() を使用する
  • 遅延評価される for result.Next(ctx) ループの後に res.Err() を確認する
  • 型アサーションをガードする(GetRecordValue[T] を使用するか、ok を確認する)
  • 管理対象トランザクションのコールバック内で副作用を発生させない
  • CALL IN TRANSACTIONS/自動コミットクエリには session.Run() を使用する
  • defer session.Close(ctx) でセッションを閉じる

コメント