数据类型及其与 Cypher 类型的映射

本节中的表格展示了 Cypher 数据类型与 Go 类型之间的映射。

访问记录内容时,所有属性的类型均为 any这意味着如果您想使用这些类型定义的方法/功能,必须将它们转换为相应的 Go 类型。例如,如果来自数据库的 name 属性是字符串,则 record.AsMap()["name"][1] 会在编译时导致无效操作错误。要使其正常工作,请在将其用作字符串之前将值转换为字符串:name := record.AsMap()["name"].(string),然后使用 name[1]

核心类型

Cypher 类型 Go 类型

NULL

nil

LIST

[]any

MAP

map[string]any

布尔值 (BOOLEAN)

bool

INTEGER(整数)

int64

FLOAT

float64

STRING

string

ByteArray

[]byte

时间类型

驱动程序提供了一套符合 ISO-8601 和 Cypher 标准的临时(时间)数据类型。亚秒级数值的测量精度可达纳秒级。

驱动程序的类型依赖于 Go 的 time 类型。实际上,除 neo4j.Duration 外的所有临时类型底层均为 time.Time 对象。这意味着:

  • 如果您想使用临时类型查询数据库,请实例化一个 time.Time 对象并将其用作查询参数(即您无需关心驱动程序的特定类型)

  • 如果您检索了一个之前通过 time.Time 对象插入的临时对象,您将获得一个 time.Time 对象(即您无需关心驱动程序的特定类型)

  • 如果您使用 Cypher 临时函数接收临时对象,您将获得下表中显示的相应驱动程序类型。您可以使用 .Time() 方法将其转换为 Go 的 time.Time 对象。

    Cypher 类型 Go 类型

    DATE

    neo4j.Date

    ZONED TIME

    neo4j.OffsetTime

    LOCAL TIME

    neo4j.LocalTime

    ZONED DATETIME

    neo4j.Time

    LOCAL DATETIME

    neo4j.LocalDateTime

    DURATION(持续时间)

    neo4j.Duration

在查询中使用临时类型
package main

import (
    "fmt"
    "context"
    "time"
    "github.com/neo4j/neo4j-go-driver/v6/neo4j"
    "reflect"
)

func main() {
    ctx := context.Background()

    // Connection to database
    dbUri := "<database-uri>"
    dbUser := "<username>"
    dbPassword := "<password>"
    driver, err := neo4j.NewDriver(
        dbUri,
        neo4j.BasicAuth(dbUser, dbPassword, ""))
    defer driver.Close(ctx)
    if err != nil {
        panic(err)
    }

    // Define a date, with timezone
    location, _ := time.LoadLocation("Europe/Stockholm")
    friendsSince := time.Date(2006, time.December, 16, 13, 59, 59, 999999999, location)

    result, err := neo4j.ExecuteQuery(ctx, driver, `
        MERGE (a:Person {name: $name})
        MERGE (b:Person {name: $friend})
        MERGE (a)-[friendship:KNOWS {since: $friendsSince}]->(b)
        RETURN friendship.since AS date
        `, map[string]any{
            "name": "Alice",
            "friend": "Bob",
            "friendsSince": friendsSince,
        }, neo4j.EagerResultTransformer,
        neo4j.ExecuteQueryWithDatabase("<database-name>"))
    if err != nil {
        panic(err)
    }
    date, _ := result.Records[0].Get("date")
    fmt.Println(reflect.TypeOf(date))  // time.Time
    fmt.Println(date)  // 2006-12-16 13:59:59.999999999 +0200 EET
}
使用驱动程序的临时类型
package main

import (
    "fmt"
    "context"
    "time"
    "github.com/neo4j/neo4j-go-driver/v6/neo4j"
    "reflect"
)

func main() {
    ctx := context.Background()

    // Connection to database
    dbUri := "<database-uri>"
    dbUser := "<username>"
    dbPassword := "<password>"
    driver, err := neo4j.NewDriver(
        dbUri,
        neo4j.BasicAuth(dbUser, dbPassword, ""))
    defer driver.Close(ctx)
    if err != nil {
        panic(err)
    }

    // Query and return a neo4j.Time object
    result, err := neo4j.ExecuteQuery(ctx, driver, `
        MERGE (a:Person {name: $name})
        MERGE (b:Person {name: $friend})
        MERGE (a)-[friendship:KNOWS {since: time()}]->(b)
        RETURN friendship.since AS time
        `, map[string]any{
            "name": "Alice",
            "friend": "Sofia",
        }, neo4j.EagerResultTransformer,
        neo4j.ExecuteQueryWithDatabase("<database-name>"))
    if err != nil {
        panic(err)
    }
    time, _ := result.Records[0].Get("time")
    fmt.Println(reflect.TypeOf(time))  // time.Time
    castDate, _ := time.(neo4j.Time)  // cast from `any` to `neo4j.Time`
    fmt.Println(castDate.Time())  // -0001-11-30 12:18:08.973 +0000 Offset
}

耗时

表示两个时间点之间的差异。

duration := neo4j.Duration{
    Months: 1,
    Days: 2,
    Seconds: 3,
    Nanos: 4,
}
fmt.Println(duration)  // 'P1Y2DT3.000000004S'

如需完整文档,请参阅 API 文档 → Duration

空间类型

Cypher 支持 空间值(点),Neo4j 可以将这些点值存储为节点和关系的属性。

对象属性 SpatialRefId(空间参考标识符的缩写)是一个数字,用于标识解释该空间类型所使用的坐标系。您可以将其视为每个空间类型的唯一标识符。

Cypher 类型 Go 类型 SpatialRefId

POINT (2D 笛卡尔坐标系)

neo4j.Point2D

7203

POINT (2D WGS-84)

neo4j.Point2D

4326

POINT (3D 笛卡尔坐标系)

neo4j.Point3D

9157

POINT (3D WGS-84)

neo4j.Point3D

4979

空间类型在 dbtype 包中实现,因此实际类型为 dbtype.Point2D/3D。不过,它们也被导入到主 neo4j 包中,因此也可以作为 neo4j.Point2D/3D 使用。

Point2D

根据 SpatialRefId 的值,Point2D 类型可用于表示二维笛卡尔点或二维世界大地测量系统 (WGS84) 点。

// A 2D Cartesian Point
cartesian2d := neo4j.Point2D{
    X:            1.23,
    Y:            4.56,
    SpatialRefId: 7203,
}
fmt.Println(cartesian2d)
// Point{srId=7203, x=1.230000, y=4.560000}

// A 2D WGS84 Point
wgs842d := neo4j.Point2D{
    X:            1.23,
    Y:            4.56,
    SpatialRefId: 9157,
}
fmt.Println(wgs842d)
// Point{srId=9157, x=1.230000, y=4.560000}

Point3D

根据 SpatialRefId 的值,Point3D 类型可用于表示三维笛卡尔点或三维世界大地测量系统 (WGS84) 点。

// A 3D Cartesian Point
cartesian3d := neo4j.Point3D{
    X:            1.23,
    Y:            4.56,
    Z:            7.89,
    SpatialRefId: 9157,
}
fmt.Println(cartesian3d)
// Point{srId=9157, x=1.230000, y=4.560000, z=7.890000}

// A 3D WGS84 Point
wgs843d := neo4j.Point3D{
    X:            1.23,
    Y:            4.56,
    Z:            7.89,
    SpatialRefId: 4979,
}
fmt.Println(wgs843d)
// Point{srId=4979, x=1.230000, y=4.560000, z=7.890000}

图类型

图类型仅作为查询结果返回,不可用作参数。.

Cypher 类型 Go 类型

NODE

dbtype.Node

RELATIONSHIP

dbtype.Relationship

PATH

dbtype.Path

Node

表示图中的一个节点。
属性 ElementId 包含实体的数据库内部标识符。使用时应格外小心,因为在单个事务范围之外,无法保证 id 值与元素之间的映射关系。换句话说,使用 ElementId 在不同事务之间进行 MATCH 操作是有风险的。

result, err := neo4j.ExecuteQuery(ctx, driver, `
    MERGE (p:Person {name: $name}) RETURN p AS person, p.name as name
    `, map[string]any{
        "name": "Alice",
    }, neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("<database-name>"))
if err != nil {
    panic(err)
}
node, _ := result.Records[0].AsMap()["person"].(neo4j.Node)
fmt.Println("Node ID:", node.ElementId)
fmt.Println("Node labels:", node.Labels)
fmt.Println("Node properties:", node.Props)

// Node ID: 4:2691aa68-87cc-467d-9d09-431df9f5c456:0
// Node labels: [Person]
// Node properties: map[name:Alice]

如需完整文档,请参阅 API 文档 → Node

Relationship

表示图中的一个关系。
属性 ElementId 包含实体的数据库内部标识符。使用时应格外小心,因为在单个事务范围之外,无法保证 id 值与元素之间的映射关系。

result, err := neo4j.ExecuteQuery(ctx, driver, `
    MERGE (p:Person {name: $name})
    MERGE (p)-[r:KNOWS {status: $status, since: date()}]->(friend:Person {name: $friendName})
    RETURN r AS friendship
    `, map[string]any{
        "name": "Alice",
        "status": "BFF",
        "friendName": "Bob",
    }, neo4j.EagerResultTransformer,
    neo4j.ExecuteQueryWithDatabase("<database-name>"))
if err != nil {
    panic(err)
}
relationship, _ := result.Records[0].AsMap()["friendship"].(neo4j.Relationship)
fmt.Println("Relationship ID:", relationship.ElementId)
fmt.Println("Relationship type:", relationship.Type)
fmt.Println("Relationship properties:", relationship.Props)
fmt.Println("Relationship start elID:", relationship.StartElementId)
fmt.Println("Relationship end elID:", relationship.EndElementId)

// Relationship ID: 5:2691aa68-87cc-467d-9d09-431df9f5c456:0
// Relationship type: KNOWS
// Relationship properties: map[since:{0 63824025600 <nil>} status:BFF]
// Relationship start elID: 4:2691aa68-87cc-467d-9d09-431df9f5c456:0
// Relationship end elID: 4:2691aa68-87cc-467d-9d09-431df9f5c456:1

如需完整文档,请参阅 API 文档 → Relationship

Path

表示图中的一条路径。

路径创建、检索和处理示例
package main

import (
    "fmt"
    "context"
    "github.com/neo4j/neo4j-go-driver/v6/neo4j"
)

func main() {
    ctx := context.Background()

    // Connection to database
    dbUri := "<database-uri>"
    dbUser := "<username>"
    dbPassword := "<password>"
    driver, err := neo4j.NewDriver(
        dbUri,
        neo4j.BasicAuth(dbUser, dbPassword, ""))
    defer driver.Close(ctx)
    if err != nil {
        panic(err)
    }

    // Create some :Person nodes linked by :KNOWS relationships
    addFriend(ctx, driver, "Alice", "BFF", "Bob")
    addFriend(ctx, driver, "Bob", "Fiends", "Sofia")
    addFriend(ctx, driver, "Sofia", "Acquaintances", "Sofia")

    // Follow :KNOWS relationships outgoing from Alice three times, return as path
    result, err := neo4j.ExecuteQuery(ctx, driver, `
        MATCH path=(:Person {name: $name})-[:KNOWS*3]->(:Person)
        RETURN path AS friendshipChain
        `, map[string]any{
            "name": "Alice",
        }, neo4j.EagerResultTransformer,
        neo4j.ExecuteQueryWithDatabase("<database-name>"))
    if err != nil {
        panic(err)
    }
    path := result.Records[0].AsMap()["friendshipChain"].(neo4j.Path)

    fmt.Println("-- Path breakdown --")
    for i := range path.Relationships {
        name := path.Nodes[i].Props["name"]
        status := path.Relationships[i].Props["status"]
        friendName := path.Nodes[i+1].Props["name"]
        fmt.Printf("%s is friends with %s (%s)\n", name, friendName, status)
    }
}

func addFriend(ctx context.Context, driver neo4j.Driver, name string, status string, friendName string) {
    _, err := neo4j.ExecuteQuery(ctx, driver, `
        MERGE (p:Person {name: $name})
        MERGE (p)-[r:KNOWS {status: $status, since: date()}]->(friend:Person {name: $friendName})
        `, map[string]any{
            "name": name,
            "status": status,
            "friendName": friendName,
        }, neo4j.EagerResultTransformer,
        neo4j.ExecuteQueryWithDatabase("<database-name>"))
    if err != nil {
        panic(err)
    }
}

如需完整文档,请参阅 API 文档 → Path

Vector

类型 Vector 映射到 Cypher 类型 VECTOR。Vector 对象作为连续的内存块存储,包含同类的值。您可以从 float64float32int8int16int32int64 的列表创建向量。

在数据库中存储 VECTOR 对象需要服务器版本 >= 2025.10,企业版。
创建、存储和检索向量
package main

import (
    "context"
    "fmt"

    "github.com/neo4j/neo4j-go-driver/v6/neo4j"
)

func main() {
    // Connection to database
    ctx := context.Background()
    dbUri := "<database-uri>"
    dbUser := "<username>"
    dbPassword := "<password>"
    driver, err := neo4j.NewDriver(
        dbUri,
        neo4j.BasicAuth(dbUser, dbPassword, ""))
    defer driver.Close(ctx)
    if err != nil {
        panic(err)
    }

    // Create a vector...
    vec := neo4j.Vector[float64]{Elems: []float64{1.0, 2.0, 3.0}}

    // ... and store it as a node property
    _, err = neo4j.ExecuteQuery(ctx, driver,
        "MERGE (n:Doc {vector: $vec})",
        map[string]any{"vec": vec},
        neo4j.EagerResultTransformer)
    if err != nil {
        panic(err)
    }

    // Retrieve the vector from the database
    result, err := neo4j.ExecuteQuery(ctx, driver,
        "MATCH (n:Doc) RETURN n.vec AS vec LIMIT 1",
        nil,
        neo4j.EagerResultTransformer)
    if err != nil {
        panic(err)
    }

    record := result.Records[0]

    if v, ok := record.Values[0].(neo4j.Vector[float64]); ok {
        fmt.Printf("Read vector: %v\n", v)
    }
    // Read vector: vector([1.0, 2.0, 3.0], 3, FLOAT64 NOT NULL)
}

UnsupportedType

类型 UnsupportedType 用于 Cypher 查询返回但驱动程序无法识别的数据类型。当客户端版本相对于服务器版本过旧时,会出现这种情况。

术语表

LTS (长期支持版)

长期支持 (Long Term Support) 版本是保证在若干年内得到支持的版本。Neo4j 4.4 和 5.26 是 LTS 版本。

Aura

Aura 是 Neo4j 的全托管云服务。它提供免费和付费计划。

Cypher

Cypher 是 Neo4j 的图查询语言,允许您从数据库中检索数据。它就像 SQL,但专用于图数据库。

APOC

Awesome Procedures On Cypher (APOC) 是一个包含(许多)函数的库,这些函数在 Cypher 本身中难以轻松实现。

Bolt

Bolt 是用于 Neo4j 实例和驱动程序之间交互的协议。默认监听 7687 端口。

ACID

原子性 (Atomicity)、一致性 (Consistency)、隔离性 (Isolation)、持久性 (Durability) (ACID) 是保证数据库事务可靠处理的属性。符合 ACID 的 DBMS 确保即使发生故障,数据库中的数据也能保持准确和一致。

最终一致性

如果一个数据库能保证所有集群成员在某个时间点都存储了数据的最新版本,则该数据库具有最终一致性。

因果一致性

如果读写查询被集群中的每个成员以相同的顺序看到,则数据库具有因果一致性。这比最终一致性更强。

NULL

空标记不是一种类型,而是缺失值的占位符。更多信息,请参阅 Cypher → 使用 null

事务

事务是一个工作单元,要么被提交,要么在失败时被回滚。例如银行转账:它涉及多个步骤,但它们必须全部成功或全部撤销,以避免钱从一个账户扣除却未存入另一个账户的情况。

背压

背压是对数据流的抵抗力。它确保客户端不会被过快发送的数据压垮,从而超出其处理能力。

书签

书签是代表数据库某种状态的标记。通过将一个或多个书签与查询一起传递,服务器将确保在所表示的状态建立之前,该查询不会被执行。

事务函数

事务函数是由 ExecuteReadExecuteWrite 调用执行的回调。如果发生服务器故障,驱动程序会自动重新执行该回调。

驱动程序 (Driver)

Driver 对象包含与 Neo4j 数据库建立连接所需的详细信息。