Go:Neo4j交易的解组结果

时间:2014-03-25 19:45:14

标签: json go neo4j unmarshalling

我试图找出解组你从Neo4j交易中获得的JSON结果的最佳方法。数据以一组列和数据的形式返回,我试图将其变成Go结构。

这是我需要结果的结构:

type Person struct {
  Id   string `json:id`
  Name string `json:name`
}

type Persons []*Person

这是我从我的交易中回来的JSON:

{
  "results":
  [
    {"columns":[],"data":[]},  
    {"columns":[],"data":[]},
    {"columns":[],"data":[]},
    {"columns":["r"],"data":   // I only care this result which has data
      [
        {"row":[{"id":"1","name":"test1"}]},  // actual results
        {"row":[{"id":"2","name":"test2"}]},
        {"row":[{"id":"3","name":"test3"}]}
      ]
    }
  ],
  "errors":[]
}

这只是一个特例。其他交易将具有可变数量的results(只是我曾经关心的最后一个)并且需要被编组到不同的结构中。我不想创建必须为每个模型结构创建一个唯一的结果结构。这是另一个例子:

这是一个不同的结构:

type Phone struct {
  Id     string `json:id`
  Number string `json:number`
}

type Phones []*Phone

相应的JSON:

{
  "results":
  [
    {"columns":[],"data":[]},  
    {"columns":["r"],"data":   // I only care this result which has data
      [
        {"row":[{"id":"4","number":"555-1234"}]},  // actual results
        {"row":[{"id":"5","number":"555-1232"}]},
        {"row":[{"id":"6","number":"555-1235"}]}
      ]
    }
  ],
  "errors":[]
}

目前我只是读出整个回复,使用字符串替换修复格式,然后正常解组,但我想知道是否有更好的方法。

以下是我希望改进的当前实施方案。

// Structures to unmarshal Neo4j transaction results into.
type transactionResponse struct {
    Results *json.RawMessage   `json:"results"`
    Errors  []transactionError `json:"errors"`
}

// req is my POST to Neo4j 
resp, err := db.client.Do(req)
defer resp.Body.Close()
if err != nil {
    return fmt.Errorf("Error posting transaction: %s", err)
}

body, err := ioutil.ReadAll(resp.Body)

var txResponse transactionResponse
if err = json.Unmarshal(body, &txResponse); err == nil {
    json.Unmarshal(formatTransactionResponse(*txResponse.Results), &Phones{});
}    

func formatTransactionResponse(data []byte) []byte {
    start := bytes.Index(data, []byte("[\"r\"]")) + 13
    data = data[start:]
    data = bytes.Replace(data, []byte("{\"row\":["), nil, -1)
    data = bytes.Replace(data, []byte("}]},{"), []byte("},{"), -1)
    data = bytes.TrimSuffix(data, []byte("}]}]"))

    //special case if no results are returned
    if len(data) == 4 {
        data = bytes.TrimSuffix(data, []byte("}]"))
    }

    return data
}

4 个答案:

答案 0 :(得分:3)

由于Neo4j输出本身就是一个结构良好的JSON结构,你可以将它解构为它自己的结构:

type Phone struct {
    Id     string `json:"id"`
    Number string `json:"number"`
}

type Output struct {
    Results []struct {
        Columns []string `json:"columns"`
        Data    []struct {
            Row []Phone `json:"row"`
        } `json:"data"`
    } `json:"results"`
    Errors []string `json:"errors"`
}

o := Output{}
err := json.Unmarshal(data, &o)

然后你用这种结构做任何你想做的事。

for _, result := range o.Results {
    if len(result.Data) > 0 {
        // Here are your phones.
        for _, d := range result.Data {
            fmt.Println(d.Row)
        }
    }
}

http://play.golang.org/p/tWc677HX1V

如果你需要,你的丑陋功能可能会更快。

答案 1 :(得分:2)

查看以下文章:http://blog.golang.org/json-and-go,"解码任意数据"部分。

您可以使用字符串键将json解码为地图,然后使用此地图访问所需的数据。

答案 2 :(得分:0)

真的没有办法处理这种冗长的协议。但最好的解决方案可能是你和Toni的答案之间的交叉,如下所示:

type transactionResponse struct {
    Results []struct {
        Columns []string
        Data    []struct {
            Row []json.RawMessage
        }
    }
    Errors []string
}

这将消除JSON的字符串处理,同时仍然只需要定义一个新类型。您可以编写一个函数来有效地从此结构中提取所需的数据并解组它。

答案 3 :(得分:0)

我不打算手动解组,只需使用标准的go数据库API和cq驱动程序:

https://github.com/wfreeman/cq

然后你可以使用sqlx为你自动解组成结构:

https://github.com/jmoiron/sqlx

这使您可以从sqlx中的结构映射优化和cq中的批处理请求中获益,以及来自两个库的所有未来改进。

这样的事情:

import (
    _ "github.com/wfreeman/cq"
    "database/sql"
    "github.com/jmoiron/sqlx"
    "log"
)

type Person struct {
    Name string `db:"first_name"`
    Email     string
}

func main() {
    db, err := sqlx.Connect("neo4j-cypher", "http://localhost:7474")
    if err != nil {
        log.Fatalln(err)
    }

    people := []Person{}
    db.Select(&people, "MATCH (n:Person) RETURN n.name AS first_name, n.email AS email")
}