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.
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
.
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)
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.
3.16.75.165