¿Una forma eficiente de consultar en un bucle for en Google App Engine?

En la documentación de GAE, establece:

Debido a que cada operación get () o put () invoca una llamada a procedimiento remoto (RPC) separada, emitir muchas de esas llamadas dentro de un bucle es una forma ineficiente de procesar una colección de entidades o claves a la vez.

Quién sabe cuántas otras ineficiencias tengo en mi código, así que me gustaría minimizar tanto como pueda. Actualmente, tengo un bucle for donde cada iteración tiene una consulta separada. Digamos que tengo un usuario, y un usuario tiene amigos. Quiero obtener las últimas actualizaciones para cada amigo del usuario. Entonces, lo que tengo es una matriz de amigos de ese usuario:

for friend_dic in friends: email = friend_dic['email'] lastUpdated = friend_dic['lastUpdated'] userKey = Key('User', email) query = ndb.gql('SELECT * FROM StatusUpdates WHERE ANCESTOR IS :1 AND modifiedDate > :2', userKey, lastUpdated) qit = query.iter() while (yield qit.has_next_async()): status = qit.next() status_list.append(status.to_dict()) raise ndb.Return(status_list) 

¿Hay una manera más eficiente de hacer esto, tal vez de alguna manera agrupar todo esto en una sola consulta?

Intente ver la función de mapa de NDB: https://developers.google.com/appengine/docs/python/ndb/queryclass#Query_map_async

Ejemplo (asumiendo que mantiene las relaciones de sus amigos en un modelo separado, para este ejemplo asumí un modelo de Relationships ):

 @ndb.tasklet def callback(entity): email = friend_dic['email'] lastUpdated = friend_dic['lastUpdated'] userKey = Key('User', email) query = ndb.gql('SELECT * FROM StatusUpdates WHERE ANCESTOR IS :1 AND modifiedDate > :2', userKey, lastUpdated) status_updates = yield query.fetch_async() raise ndb.Return(status_updates) qry = ndb.gql("SELECT * FROM Relationships WHERE friend_to = :1", user.key) updates = yield qry.map_async(callback) #updates will now be a list of status updates 

Actualizar:

Con una mejor comprensión de su modelo de datos:

 queries = [] status_list = [] for friend_dic in friends: email = friend_dic['email'] lastUpdated = friend_dic['lastUpdated'] userKey = Key('User', email) queries.append(ndb.gql('SELECT * FROM StatusUpdates WHERE ANCESTOR IS :1 AND modifiedDate > :2', userKey, lastUpdated).fetch_async()) for query in queries: statuses = yield query status_list.extend([x.to_dict() for x in statuses]) raise ndb.Return(status_list) 

Podrías realizar esas consultas simultáneamente usando métodos asíncronos ndb:

 from google.appengine.ext import ndb class Bar(ndb.Model): pass class Foo(ndb.Model): pass bars = ndb.put_multi([Bar() for i in range(10)]) ndb.put_multi([Foo(parent=bar) for bar in bars]) futures = [Foo.query(ancestor=bar).fetch_async(10) for bar in bars] for f in futures: print(f.get_result()) 

Esto lanza 10 RPC de consulta del almacén de datos concurrentes, y la latencia general solo depende de la más lenta en lugar de la sum de todas las latencias

También vea la documentación oficial de ndb para obtener más detalles sobre cómo asyncar las API con ndb.