【问题标题】:App Engine Datastore: How to set multiple values on a property using golang?App Engine Datastore:如何使用 golang 在属性上设置多个值?
【发布时间】:2026-01-22 02:15:01
【问题描述】:

我正在尝试使用 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)

但没有“数据存储区:无效的实体类型”错误。

【问题讨论】:

    标签: google-app-engine go google-cloud-datastore


    【解决方案1】:

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

    如果结构字段是切片类型,它将自动成为多值属性。此代码有效:

    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 的单独/不同实体,例如由PostKey 或最好只是它的IntID

    【讨论】:

      【解决方案2】:

      您的程序语法错误。

      您确定您正在运行您认为正在运行的代码吗?例如,您的 Post 没有必要的逗号来分隔键/值对。

      go fmt 应该报告语法错误。

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

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

      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)
      }
      

      【讨论】: