我试图找出解组你从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
}
答案 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")
}