App Engine Datastore:如何使用 golang 在 属性 上设置多个值?

App Engine Datastore: How to set multiple values on a property using golang?

我正在尝试使用 Golang 在 Google 的数据存储中为单个 属性 保存多个值。

我有一片 int64,我希望能够存储和检索。从文档中我可以看到通过实现 PropertyLoadSaver{} 接口支持这一点。但是我似乎想不出一个正确的实现方式。

基本上,这就是我想要完成的:

type Post struct {
    Title         string
    UpVotes       []int64 `json:"-" xml:"-" datastore:",multiple"`
    DownVotes     []int64 `json:"-" xml:"-" datastore:",multiple"`
}

c := appengine.NewContext(r)
p := &Post{
    Title: "name"
    UpVotes: []int64{23, 45, 67, 89, 10}
    DownVotes: []int64{90, 87, 65, 43, 21, 123}
}
k := datastore.NewIncompleteKey(c, "Post", nil)
err := datastore.Put(c, k, p)

但没有 "datastore: invalid entity type" 错误。

您的程序在语法上有问题。

您确定您是 运行 您认为自己是 运行 的代码吗?例如,您的 Post 没有分隔 key/value 对的必要逗号。

A go fmt 应该报告语法错误。

此外,datastore.Put() returns 多个值(键和错误),代码只需要一个值。此时您应该遇到编译时错误。

首先纠正这些问题:当程序无法编译时,追逐幻象语义错误是没有意义的。这是您的程序的一个版本,不会引发编译时错误。

package hello

import (
    "appengine"
    "appengine/datastore"
    "fmt"
    "net/http"
)

type Post struct {
    Title     string
    UpVotes   []int64 `json:"-" xml:"-" datastore:",multiple"`
    DownVotes []int64 `json:"-" xml:"-" datastore:",multiple"`
}

func init() {
    http.HandleFunc("/", handler)
}

func handler(w http.ResponseWriter, r *http.Request) {
    c := appengine.NewContext(r)
    p := &Post{
        Title:     "name",
        UpVotes:   []int64{23, 45, 67, 89, 10},
        DownVotes: []int64{90, 87, 65, 43, 21, 123},
    }
    k := datastore.NewIncompleteKey(c, "Post", nil)
    key, err := datastore.Put(c, k, p)

    fmt.Fprintln(w, "hello world")
    fmt.Fprintln(w, key)
    fmt.Fprintln(w, err)
}

AppEngine 默认支持多值属性,您无需执行任何特殊操作即可使其正常工作。您不需要实现 PropertyLoadSaver 接口,也不需要任何特殊的标记值。

如果一个struct字段是slice类型,它会自动成为一个多值属性。此代码有效:

type Post struct {
    Title         string
    UpVotes       []int64
    DownVotes     []int64
}

c := appengine.NewContext(r)
p := &Post{
    Title: "name",
    UpVotes: []int64{23, 45, 67, 89, 10},
    DownVotes: []int64{90, 87, 65, 43, 21, 123},
}
k := datastore.NewIncompleteKey(c, "Post", nil)
key, err := datastore.Put(c, k, p)
c.Infof("Result: key: %v, err: %v", key, err)

当然,如果您愿意,可以为 json 和 xml 指定标签值:

type Post struct {
    Title         string
    UpVotes       []int64 `json:"-" xml:"-"`
    DownVotes     []int64 `json:"-" xml:"-"`
}

备注:

但请注意,如果 属性 被索引,多值属性不适合存储大量值。这样做将需要许多索引(许多写入)来存储和修改实体,并且您可能会达到实体的索引限制(有关详细信息,请参阅 Index limits and Exploding indexes)。

例如,您不能使用多值 属性 来存储 Post 的数百个赞成票和反对票。为此,您应该将投票存储为链接到 Post 的 separate/different 实体,例如通过 PostKey 或者最好只是它的 IntID.