Appengine>执行>映射数据存储区结果

I'm trying to map the results retreived by query.GetAll()

I need to map the results since the Template will need the datastore 'Key' associated with each entity.

At the moment I'm doing the following:

// Query
q := datastore.NewQuery("Article").Limit(10)
// Define array where the entities will be retreived
var a[] Article;
// Retreive entities
key, _ := q.GetAll(c, &a)
// Create an empty map
article := map[string] Article{}
// Build the map
for k := range a {
    article[key[k].Encode()] = a[k];
}
template.Execute(w, map[string]interface{} { "Articles" : article})

Is there a more efficient way to build the map directly using query.GetAll(), since creating an array, a map and loop over the array to build the map doesn't seem wise?

Or a more efficient way to get the datastore Key (Encoded) associated with each entity?

I don't think you need the map. If I understand, after GetAll, you have two parallel slices, key and a. (I don't know GAE, but the _ raises my eyebrow. Is it something you should check?) Templates can handle parallel arrays. See in the doc how the range action can return two results, a value and and index. You should be able to range over one slice and use the index to get corresponding values from the other. It will be a more complex template, but should let you avoid the map.

Edit: Sorry, I thought I knew how to do this, but failed when I tried to code an example. I'll leave it here in case someone else knows how to do this, otherwise, downvote...

Maybe best is to zip the slices into a single slice. Along these lines,

package main

import (
    "os"
    "text/template"
)

type pair struct {
    Key     string
    Article string
}

var tmpt = `Here's the list:{{range $p := .}}
    {{$p.Key}}: {{$p.Article}}{{end}}
`

func main() {
    list := template.Must(template.New("list").Parse(tmpt))
    // query
    key := []string{"banana", "donkey", "curious"}
    a := []string{"long fruit", "who needs one?", "human nature"}
    // zip
    pairs := make([]pair, len(key))
    for i, k := range key {
        pairs[i].Key = k
        pairs[i].Article = a[i]
    }
    // execute on zipped list
    if err := list.Execute(os.Stdout, pairs); err != nil {
        os.Stdout.WriteString(err.Error())
    }
}

Output:

Here's the list:
        banana: long fruit
        donkey: who needs one?
        curious: human nature

Maybe you could embedding the Key in the Article. You would still have to loop over the articles and keys, but at least you wouldn't have to create a separate map.

type Article struct {
    // Add a key to the struct, but prevent it from being saved to the datastore.
    Key datastore.Key `datastore:"-"`
}

// Query
q := datastore.NewQuery("Article").Limit(10)
// Define array where the entities will be retreived
var a[] Article
// Retreive entities
key, _ := q.GetAll(c, &a)

// Loop through the articles adding the key as you go.
for i := range a {
    a[i].Key = key[i]
}
template.Execute(w, map[string]interface{} { "Articles" : a})

Then in your template you would call article.Key.Encode