数据类型及其到 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.Date 对象。这意味着:

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

  • 如果您检索之前从 time.Date 对象插入的时间对象,您将获得一个 time.Date 对象(即,您无需关心驱动程序的类型)

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

    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/v5/neo4j"
    "reflect"
)

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

    // Connection to database
    dbUri := "{neo4j-database-uri}"
    dbUser := "{neo4j-username}"
    dbPassword := "{neo4j-password}"
    driver, _ := neo4j.NewDriverWithContext(
        dbUri,
        neo4j.BasicAuth(dbUser, dbPassword, ""))
    driver.VerifyConnectivity(ctx)

    // 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("neo4j"))
    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/v5/neo4j"
    "reflect"
)

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

    // Connection to database
    dbUri := "{neo4j-database-uri}"
    dbUser := "{neo4j-username}"
    dbPassword := "{neo4j-password}"
    driver, _ := neo4j.NewDriverWithContext(
        dbUri,
        neo4j.BasicAuth(dbUser, dbPassword, ""))
    driver.VerifyConnectivity(ctx)

    // 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("neo4j"))
    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

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

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

Point2D 类型可用于表示 2D 笛卡尔点或 2D 世界大地测量系统 (WGS84) 点,具体取决于 SpatialRefId 的值。

// 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

Point3D 类型可用于表示 3D 笛卡尔点或 3D 世界大地测量系统 (WGS84) 点,具体取决于 SpatialRefId 的值。

// 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 类型 Python 类型

NODE

dbtype.Node

RELATIONSHIP

dbtype.Relationship

PATH

dbtype.Path

Node

表示图中的一个节点。
属性 ElementId 包含实体的数据库内部标识符。应谨慎使用此属性,因为在单个事务范围之外,不能保证 ID 值与元素之间的映射关系。换句话说,跨不同事务使用 ElementIdMATCH 元素是有风险的。

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("neo4j"))
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("neo4j"))
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/v5/neo4j"
)

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

    // Connection to database
    dbUri := "{neo4j-database-uri}"
    dbUser := "{neo4j-username}"
    dbPassword := "{neo4j-password}"
    driver, _ := neo4j.NewDriverWithContext(
        dbUri,
        neo4j.BasicAuth(dbUser, dbPassword, ""))
    driver.VerifyConnectivity(ctx)

    // 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("neo4j"))
    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.DriverWithContext, 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("neo4j"))
    if err != nil {
        panic(err)
    }
}

有关完整文档,请参阅 API 文档 → Path

异常

在大多数情况下,驱动程序只是简单地转发服务器可能引发的任何错误。有关服务器可能返回的错误列表,请参阅状态码页面。

某些服务器错误被标记为可以安全重试,无需更改原始请求。此类错误的示例包括死锁、内存问题或连接问题。当引发错误时,函数 neo4j.IsRetryable(error) 提供了关于进一步尝试是否可能成功的见解。这在显式事务中运行查询时特别有用,可以知道失败的查询是否应该再次运行。请注意,托管事务已实现重试机制,因此您无需实现自己的重试机制。

术语表

LTS

长期支持版本是指保证支持多年的版本。Neo4j 4.4 是 LTS 版本,Neo4j 5 也将有 LTS 版本。

Aura

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

Cypher

Cypher 是 Neo4j 的图查询语言,可让您从数据库中检索数据。它类似于 SQL,但专用于图。

APOC

Awesome Procedures On Cypher (APOC) 是一个(许多)难以用 Cypher 本身表达的函数的库。

Bolt

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

ACID

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

最终一致性

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

因果一致性

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

NULL

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

事务

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

反压

反压是阻止数据流动的力。它确保客户端不会被快于其处理能力的数据淹没。

事务函数

事务函数是由 ExecuteReadExecuteWrite 调用执行的回调。驱动程序在服务器失败时会自动重新执行回调。

DriverWithContext

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

© . All rights reserved.