Storing Data

This page shows how to store guestbook greetings posted by users using Cloud Datastore.

This page is part of a multi-page tutorial. To start from the beginning and see instructions for setting up, go to Creating a Guestbook.

Creating and filling a greeting

The sample code uses a Go struct named Greeting:

type Greeting struct {
	Author  string
	Content string
	Date    time.Time

Each greeting includes the author's name, the message content, and the date and time the message was posted so you can display messages in chronological order.

For a new Greeting, the Content field contains the data posted by the user, the Date field contains the current time, and the Author field contains the current user:

Saving a greeting to Cloud Datastore

The code sample saves new values to Cloud Datstore with datastore.Put. If you pass a new, incomplete key, Cloud Datastore creates a new key for this record automatically:

func sign(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	g := Greeting{
		Content: r.FormValue("content"),
		Date:    time.Now(),
	if u := user.Current(c); u != nil {
		g.Author = u.String()
	// We set the same parent key on every Greeting entity to ensure each Greeting
	// is in the same entity group. Queries across the single entity group
	// will be consistent. However, the write rate to a single entity group
	// should be limited to ~1/second.
	key := datastore.NewIncompleteKey(c, "Greeting", guestbookKey(c))
	_, err := datastore.Put(c, key, &g)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	http.Redirect(w, r, "/", http.StatusFound)

Retrieving a greeting

The datastore package provides a Query type for querying the datastore and iterating over the results.

The sample code queries Cloud Datastore for greetings in the root handler:

func root(w http.ResponseWriter, r *http.Request) {
	c := appengine.NewContext(r)
	// Ancestor queries, as shown here, are strongly consistent with the High
	// Replication Datastore. Queries that span entity groups are eventually
	// consistent. If we omitted the .Ancestor from this query there would be
	// a slight chance that Greeting that had just been written would not
	// show up in a query.
	q := datastore.NewQuery("Greeting").Ancestor(guestbookKey(c)).Order("-Date").Limit(10)
	greetings := make([]Greeting, 0, 10)
	if _, err := q.GetAll(c, &greetings); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	if err := guestbookTemplate.Execute(w, greetings); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)

The following code constructs a Query value that requests the 10 most recent Greeting objects that are descendants of the root guestbook key in Date-descending order:

q := datastore.NewQuery("Greeting").Ancestor(guestbookKey(c)).Order("-Date").Limit(10)

The following code calls q.GetAll(c, &greetings) to run the query and append the results to the greetings slice:

greetings := make([]Greeting, 0, 10)
if _, err := q.GetAll(c, &greetings); err != nil {
	http.Error(w, err.Error(), http.StatusInternalServerError)

For more information on queries, see Datastore Queries.

Specifying a custom index

The guestbook application filters by entry and orders by date using an ancestory query and a sort order, so it requires a custom index. There are two ways to specify a custom index:

  • Run queries in your application locally, which automatically creates the required indexes in index.yaml. This is the easiest method.
  • Manually edit this file to supply indexes you know you need.

The following index is required for the query in the index.yaml file for the guestbook application:

- kind: Greeting
  ancestor: yes
  - name: Date
    direction: desc

After you define your index in index.yaml, deploying your application will also upload that custom index information.

For more information, see Go Datastore Index Configuration and Datastore Indexes.

Clearing the development server

The development web server uses a local version of the datastore for testing your application, using temporary files. The data persists as long as the temporary files exist, and the web server does not reset these files unless you ask it to do so.

If you want the development server to erase its datastore prior to starting up, see the Go Development Server reference, which explains the datastore configuration options for the development server.

Send feedback about...

App Engine standard environment for Go