App Engine Datastore: How to set multiple values o

2019-06-10 09:36发布

I am trying to save multiple values for a single property in Google's Datastore using Golang.

I have a slice of int64 that I would like to be able to store and retrieve. From the documentation I can see that there is support for this by implementing the PropertyLoadSaver{} interface. But I cannot seem to come up with a correct implementation.

Essentially, this is what I'd like to accomplish:

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)

But without the "datastore: invalid entity type" error.

2条回答
淡お忘
2楼-- · 2019-06-10 09:40

Your program is syntactically malformed.

Are you sure you're running the code you think you're running? For example, your Post doesn't have necessary commas that delimit the key/value pairs.

A go fmt should be reporting syntax errors.

Also, datastore.Put() returns multiple values (the key and the error), and the code is only expecting a single value. You should be getting compile-time errors at this point.

Correct those issues first: there no point chasing after phantom semantic errors when the program doesn't compile. Here is a version of your program that doesn't raise compile-time errors.

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)
}
查看更多
疯言疯语
3楼-- · 2019-06-10 09:55

Multi-valued properties are supported by AppEngine by default, you don't need to do anything special to make it work. You don't need to implement the PropertyLoadSaver interface, and you don't need any special tag value.

If a struct field is of a slice type, it will automatically be a multi-valued property. This code works:

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)

Of course if you want you can specify tag value for json and xml:

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

Notes:

But please note that multi-valued properties are not suitable to store a large number of values if the property is indexed. Doing so would require many indices (many writes) to store and modify the entity, and potentially you could hit the index limit for an entity (see Index limits and Exploding indexes for more details).

So for example you can't use a multi-valued property to store hundreds of up- and downvotes for a Post. For that you should store votes as separate/different entities linking to the Post e.g. by the Key of the Post or preferably just its IntID.

查看更多
登录 后发表回答