I experiment a little bit with GAE, but now I have a problem. First of all I store some stuff into the datastore, with an NewIncompleteKey.
So there is the issue. My Website sends timestamps (I handle them as "ID"s) to the back-end. I parse then and want to delete them from the datastore.
I thought I can do this.
type Food struct{
Id int64
Course string
Name string
Date string
Price float64
}
...Some Code...
func deleteEntries(mealsID []string, r *http.Request) int{
// Get context from
c := appengine.NewContext(r);
for _,id := range mealsID{
var key *datastore.Key = nil
q := datastore.NewQuery("Meal").Ancestor(mealStoreKey(c)).Filter("Course =", "dessert").KeysOnly()
_, err := q.GetAll(c, key)
if err != nil{
return 0
}
log.Printf("Here the keys: %T %v ", key, key)
log.Printf("%v ", id)
e := datastore.Delete(c, key)
if e != nil{
return 33
}
}
return len(mealsID)
}
But it doesn't work, because I get an error at the datastore.Delete() function. Anyone an idea?
Edit:
Part I:
keys, err := q.GetAll(c, nil)
…
err = datastore.DeleteMulti(c, keys)
Thanks to Dave.
Part II:
I passed an String as Filter vaule to the query, but it have to be an Int64 same as in the datastore. Note to my self: You have to pass also the same type of var to the query.
func deleteEntries(mealsID []string, r *http.Request) int{
// Get context from
c := appengine.NewContext(r);
for _,id := range mealsID{
ID,_ := strconv.Atoi(id)
q:= datastore.NewQuery("Meal").Ancestor(mealStoreKey(c)).Filter("Id =", ID ).KeysOnly()
keys, err := q.GetAll(c, nil)
if err != nil{
return 0
}
log.Printf("ID: %v ", id)
log.Printf("Keys: %v ", keys)
e := datastore.DeleteMulti(c, keys)
if e != nil{
log.Printf("%v ", e)
return 0
}
}
return len(mealsID)
}
The keys are returned from GetAll. So you should instead write:
keys, err := q.GetAll(c, nil)
…
err = datastore.DeleteMulti(c, keys)
GetAll ignores the dst parameter for keys-only requests – datastore reference. So, in the example above, key will still be set to nil which explains the error.
Related
I am writing a service for search functionality. when i am passing values in the body to get the specific record i am unable to get it based on the struct value.
ex:phone number or username
Edit1:
type PatientData struct {
ID int64 datastore:"-"
FirstName string json:"firstname,omitempty"
LastName string json:"lastname,omitempty"
UserName string json:"username,omitempty"
Phone string json:"phone,omitempty"
}
I want to get the full struct values based on Username or Phone. Below is my code:
func searchValue (res http.ResponseWriter, req *http.Request){
log.Printf("%#v Getting values url - x ", "called search")
patient := &PatientData{}
if err := json.NewDecoder(req.Body).Decode(patient); err != nil {
panic(err)
}
ctx := appengine.NewContext(req)
ctx, err := appengine.Namespace(ctx, NAMESPACENAME)
if err != nil {
panic(err)
}
m := patient.Phone
i, err := strconv.ParseInt(m, 10, 64)
log.Printf("%#v Getting values m ", m)
log.Printf("%#v Getting values url -yyy ",i)
key := datastore.NewKey(ctx, "Patient","" , i, nil)
log.Printf("%#v Getting values url - key ", key)
err = datastore.Get(ctx, key, patient)
if err := json.NewEncoder(res).Encode(patient); err != nil {
panic(err)
}
}
As i am passing PHONE in my Newkey i am unable to generate the values based on PHONE
I don't want to use Newkey in put functionality to generate a keyname and based on that KEYNAME i dont want to get Values.
datastore.Get() can only be used to get an entity from the datastore by its key, so its key must be known / present.
This is obviously not what you're trying to do. You are trying to fetch entities by properties which are not the key. To do that, you need to run a query.
Datastore queries are represented by the datastore.Query type. You need to create a query and set filters on it. In your case, you want to filter by the username and/or phone properties.
This is how it could look like. Fetch patient entities filtered by phone:
q := datastore.NewQuery("Patient").Filter("phone =", patient.Phone)
var patients []*Patient
keys, err := q.GetAll(ctx, &patients)
if err != nil {
// Handle error
return
}
// patients contains patients with the given phone number
An example fetching patients filtered by phone number AND user name:
q := datastore.NewQuery("Patient").
Filter("phone =", patient.Phone).
Filter("username =", patient.UserName)
var patients []*Patient
keys, err := q.GetAll(ctx, &patients)
if err != nil {
// Handle error
return
}
// patients contains patients with the given phone number and username
I am trying to store datastore record in namespace MyNameSpace with GAE/Go, but the code below not working.
import (
"cloud.google.com/go/datastore"
"github.com/gin-gonic/gin"
"google.golang.org/appengine"
)
func Save(c *gin.Context, list []MyStruct) ([]MyStruct, error) {
r := c.Request
ctx := appengine.NewContext(r)
ctx_with_namespace, err := appengine.Namespace(ctx, "MyNameSpace")
if err != nil {
return nil, err
}
client, err := datastore.NewClient(ctx_with_namespace, "MyProject")
if err != nil {
return nil, err
}
var keyList []*datastore.Key
for _, v := range list {
key := datastore.NameKey("MyStruct", v.ColA, nil)
keyList = append(keyList, key)
}
_, err = client.PutMulti(ctx_with_namespace, keyList, list)
return list,nil
}
This code creates records in the default namespace, not MyNameSpace.
Does cloud.google.com/go/datastore ignores namespace setting?
I found this document
November 8, 2016
Breaking changes to datastore: contexts no longer hold namespaces;
instead you must set a key's namespace explicitly. Also, key functions
have been changed and renamed.
The WithNamespace function has been removed. To specify a namespace in
a Query, use the Query.Namespace method:
q := datastore.NewQuery("Kind").Namespace("ns")
All the fields of Key are exported. That means you can construct any Key with a struct literal:
k := &Key{Kind: "Kind", ID: 37, Namespace: "ns"}
I realized I should explicitly set namespace, but it is very inconvenient. I migrated to use google.golang.org/appengine/datastore
I have a simple question, I been playing with dev_appserver testing my Go app locally.
I saved some keys:
client, err = datastore.NewClient(ctx, utils.ProjectID)
key := datastore.NewKey(ctx, KindSpace, "", id, nil)
if _, err := client.Put(ctx, key, value); err != nil {
return err
}
However, When connecting to: http://localhost:8000/datastore my datastore is empty.
I then tried to retrieve the keys from inside my code using:
client, err = datastore.NewClient(ctx, utils.ProjectID)
entity := new(Space)
key := datastore.NewKey(ctx, KindSpace, "", id, nil)
if err := client.Get(ctx, key, entity); err != nil {
return nil, err
}
and indeed it returned the keys I saved. Do you have any idea what do I miss? Does it have something to do with the database namespace maybe?
Is there anyway to read the local data base from the terminal?
I'm trying to find an effective example in how to perform updates on appengine datastore with Go.
All the examples I've found on the web are very vague and mostly explains concepts and not the "real life".
The appengine documentation for go says:
..."Updating an existing entity is a matter of performing another Put() using the same key."
My problem here is being in how to retrieve the key. So I have the code below to store and retrieve data:
func subscribe(w http.ResponseWriter, r *http.Request) {
user := User {
Name: r.FormValue("username"),
Email: r.FormValue("useremail"),
Flag: 0,
}
c := appengine.NewContext(r)
//datastore.Put(c, datastore.NewIncompleteKey(c, "User", nil), &user)
datastore.Put(c, datastore.NewKey(c, "User", "stringID", 0, nil), &user)
template.Must(template.ParseFiles("confirmation.html")).Execute(w, nil)
}
func checkusers(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
qUsers := datastore.NewQuery("User")
var users []User
qUsers.GetAll(c, &users)
template.Must(template.ParseFiles("users.html")).Execute(w, users)
}
How do I do an update on the flag property changing its value tom 1?
I'm a bit confused on this thing as I couldn't fully understand how the "key" is stored for each entity.
Any help would be very appreciated.
todo an update you first need to identify if your object is a new or an old one.
this can be simple done by adding the following method to your User struct:
type User struct {
Name string
Email string
Flag int64 `datastore:"-"`
}
func (u *User) IsNew() bool {
return u.Flag == 0
}
this tells data-store to ignore the Flag field when storing and retrieving an object
and because initial value of int64 is zero, a newly created object can be identified if Flag is zero
so creating a new object just needs to set UserName and Email:
user := User {
Name: r.FormValue("username"),
Email: r.FormValue("useremail")
}
then next step is to either use a IncompleteKey or a Key, for the put statement
could look like this:
var k *datastore.Key
if user.IsNew() {
k = datastore.NewIncompleteKey(c, "Users", nil)
} else {
k = datastore.NewKey(c, "Users", "", user.Flag, nil)
}
k, err := datastore.Put(c, k, user)
if err != nil {
return k, err
}
with an incomplete key, app-engine will generate a new key for you.
after put you can assign the new key to your object:
user.Flag = k.IntID
now if you do a query later you need to assign the Id to your query result objects,
the query will return the keys of query result in the same order so you can change your code like this:
keys, err := q.GetAll(c, &users)
if err != nil {
return
}
l := len(users)
for i := 0; i < l; i++ {
users[i].Flag = keys[i].IntID()
}
thats all, for more information, just have a look a the reference document there is explained with methods return which values.
https://developers.google.com/appengine/docs/go/datastore/reference
Here is an Example of the app. The essential code is in: golang-code/handler/handler.go (After the subject should appear an ID!)
Im trying to build a little blog system in Golang on Google Appengine and use Mustache as template engine.
So, i have a struct:
type Blogposts struct {
PostTitle string
PostPreview string
Content string
Creator string
Date time.Time
}
The data is passed to GAE via
datastore.Put(c, datastore.NewIncompleteKey(c, "Blogposts", nil), &blogposts)
So, GAE assigns automatically a intID (int64).
Now I tried to get the latest blogposts
// Get the latest blogposts
c := appengine.NewContext(r)
q := datastore.NewQuery("Blogposts").Order("-Date").Limit(10)
var blogposts []Blogposts
_, err := q.GetAll(c, &blogposts)
Until there all things works fine, but when I try to access intID (or stringID, whatever) I dont have access to this :-(
<h3>{{{PostTitle}}}</h3>
(PostTitle works, intID not, i've tried thousand of things, nothing worked :-( )
Anyone an idea? This would be great!
Edit:
I use mustache.
http://mustache.github.com/
In the code I use:
x["Blogposts"] = blogposts
data := mustache.RenderFile("templates/about.mustache", x)
sendData(w, data) // Equivalent to fmt.Fprintf
And then the data can be accessed in the .mustache template with {{{Content}}} or {{{PostTitle}}} etc.
As hyperslug pointed out, the id field of an entity is on the key, not the struct it gets read into.
Another way around this is to add an id field to your struct and tell datastore to ignore it, eg:
type Blogposts struct {
PostTitle string
PostPreview string
Content string
Creator string
Date time.Time
Id int64 `datastore:"-"`
}
You can then populate the Id field manually after a call to GetAll() like so
keys, err := q.GetAll(c, &blogposts)
if err != nil {
// handle the error
return
}
for i, key := range keys {
blogposts[i].Id = key.IntID()
}
This has the benefit of not introducing an extra type.
intID is an internal property of a Key not the struct, and is accessible through a getter:
id := key.IntID()
GetAll returns []*Key, which you're not using:
_, err := q.GetAll(c, &blogposts)
One way to get around this is to create a viewmodel struct that has both your post and key info (untested, but this is the gist of it):
//... handler code ...
keys, err := q.GetAll(c, &blogposts)
if err != nil {
http.Error(w, "Problem fetching posts.", http.StatusInternalServerError)
return
}
models := make([]BlogPostVM, len(blogposts))
for i := 0; i < len(blogposts); i++ {
models[i].Id = keys[i].IntID()
models[i].Title = blogposts[i].Title
models[i].Content = blogposts[i].Content
}
//... render with mustache ...
}
type BlogPostVM struct {
Id int
Title string
Content string
}
I know this question is a couple years old, but the following article was very helpful to me in this regard: Golang basics with Google Datastore.
In the article, the author provides a nice example of how you can run a query that gets an entity by its ID...
func GetCategory(c appengine.Context, id int64) (*Category, error) {
var category Category
category.Id = id
k := category.key(c)
err := datastore.Get(c, k, &category)
if err != nil {
return nil, err
}
category.Id = k.IntID()
return &category, nil
}
...as well as getting a list/collection of entities with their associated ID:
func GetCategories(c appengine.Context) ([]Category, error) {
q := datastore.NewQuery("Category").Order("Name")
var categories []Category
keys, err := q.GetAll(c, &categories)
if err != nil {
return nil, err
}
// you'll see this a lot because instances
// do not have this by default
for i := 0; i < len(categories); i++ {
categories[i].Id = keys[i].IntID()
}
return categories, nil
}
The snippet above is very close to the helpful answer by #koz.
AFAICS, the Blogposts struct has no field intID, but it has a field PostTitle. I guess that could be the reason why the former doesn't and the later does get rendered, though I've never used Mustache...