Querying in Google Cloud Datastore

So far, we have only been putting and getting single objects into and out of Google Cloud Datastore. When we display a list of answers to a question, we want to load all of these answers in a single operation, which we can do with datastore.Query.

The querying interface is a fluent API, where each method returns the same object or a modified object, allowing you to chain calls together. You can use it to build up a query consisting of ordering, limits, ancestors, filters, and so on. We will use it to write a function that will load all the answers for a given question, showing the most popular (those with a higher Score value) first.

Add the following function to answers.go:

func GetAnswers(ctx context.Context, questionKey *datastore.Key)  
([]*Answer, error) { 
  var answers []*Answer 
  answerKeys, err := datastore.NewQuery("Answer"). 
    Ancestor(questionKey). 
    Order("-Score"). 
    Order("-CTime"). 
    GetAll(ctx, &answers) 
  for i, answer := range answers { 
    answer.Key = answerKeys[i] 
  } 
  if err != nil { 
    return nil, err 
  } 
  return answers, nil 
} 

We first create an empty slice of pointers to Answer and use datastore.NewQuery to start building a query. The Ancestor method indicates that we're looking only for answers that belong to the specific question, where the Order method calls specify that we want to first order by descending Score and then by the newest first. The GetAll method performs the operation, which takes in a pointer to our slice (where the results will go) and returns a new slice containing all the keys.

Tip

The order of the keys returned will match the order of the entities in the slice. This is how we know which key corresponds to each item.

Since we are keeping keys and the entity fields together, we range over the answers and assign answer.Key to the corresponding datastore.Key argument returned from GetAll.

Note

We are keeping our API simple for the first version by not implementing paging, but ideally you would need to; otherwise, as the number of questions and answers grows, you will end up trying to deliver everything in a single request, which would overwhelm the user and maybe the servers.

If we had a step in our application of authorizing the answer (to protect it from spam or inappropriate content), we might want to add an additional filter for Authorized to be true, in which case we could do this:

datastore.NewQuery("Answer"). 
 Filter("Authorized =", true) 

Tip

For more information on querying and filtering, consult the Google Cloud Datastore API documentation online.

Another place where we need to query data is when we show the top questions on the home page of our app. Our first version of top questions will just show those questions that have the most answers; we consider them to be the most interesting, but you could change this functionality in the future without breaking the API to order by score or even question views.

We will build Query on the Question kind and use the Order method to first order by the number of answers (with the highest first), followed by time (also, highest/latest first). We will also use the Limit method to make sure we only select the top 25 questions for this API. Later, if we implement paging, we can even make this dynamic.

In questions.go, add the TopQuestions function:

func TopQuestions(ctx context.Context) ([]*Question, error) { 
  var questions []*Question 
  questionKeys, err := datastore.NewQuery("Question"). 
    Order("-AnswersCount"). 
    Order("-CTime"). 
    Limit(25). 
    GetAll(ctx, &questions) 
  if err != nil { 
    return nil, err 
  } 
  for i := range questions { 
    questions[i].Key = questionKeys[i] 
  } 
  return questions, nil 
} 

This code is similar to loading the answers, and we end up returning a slice of Question objects or an error.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.93.0