App Engine Datastore IN Operator - come utilizzare?
-
05-07-2019 - |
Domanda
Lettura: http://code.google.com/appengine /docs/python/datastore/gqlreference.html
Voglio usare:
: = IN
ma non sono sicuro di come farlo funzionare. Supponiamo che
class User(db.Model):
name = db.StringProperty()
class UniqueListOfSavedItems(db.Model):
str = db.StringPropery()
datesaved = db.DateTimeProperty()
class UserListOfSavedItems(db.Model):
name = db.ReferenceProperty(User, collection='user')
str = db.ReferenceProperty(UniqueListOfSavedItems, collection='itemlist')
Come posso fare una query che mi dia l'elenco degli elementi salvati per un utente? Ovviamente posso fare:
q = db.Gql("SELECT * FROM UserListOfSavedItems WHERE name :=", user[0].name)
ma questo mi dà un elenco di chiavi. Voglio ora prendere quell'elenco e inserirlo in una query per estrarre il campo str da UniqueListOfSavedItems. Pensavo di poter fare:
q2 = db.Gql("SELECT * FROM UniqueListOfSavedItems WHERE := str in q")
ma qualcosa non va ... qualche idea? È (sono al mio lavoro quotidiano, quindi non posso provarlo ora):
q2 = db.Gql("SELECT * FROM UniqueListOfSavedItems __key__ := str in q)
nota a margine: che problema diabolicamente difficile da cercare perché tutto quello che mi interessa davvero è il " IN " operatore.
Soluzione
Dato che hai un elenco di chiavi, non è necessario eseguire una seconda query, puoi invece eseguire un recupero batch. Prova questo:
#and this should get me the items that a user saved
useritems = db.get(saveditemkeys)
(Nota che non è nemmeno necessaria la clausola di guardia - un db.get su 0 entità è cortocircuitato in modo appropriato.)
Qual è la differenza, potresti chiedere? Bene, un db.get richiede circa 20-40ms. Una query, d'altra parte (GQL o no) richiede circa 160-200ms. Ma aspetta, peggiora! L'operatore IN è implementato in Python e si traduce in più query, che vengono eseguite in serie. Quindi, se si esegue una query con un filtro IN per 10 chiavi, si eseguono 10 operazioni di query separate da 160 ms, per un totale di circa 1,6 secondi di latenza. Un singolo db.get, al contrario, avrà lo stesso effetto e prenderà un totale di circa 30ms.
Altri suggerimenti
+1 a Adam per avermi portato sulla strada giusta. Sulla base del suo puntatore e facendo qualche ricerca su Ricerca codice, ho la seguente soluzione.
usersaveditems = User.Gql(“Select * from UserListOfSavedItems where user =:1”, userkey)
saveditemkeys = []
for item in usersaveditems:
#this should create a list of keys (references) to the saved item table
saveditemkeys.append(item.str())
if len(usersavedsearches > 0):
#and this should get me the items that a user saved
useritems = db.Gql(“SELECT * FROM UniqueListOfSavedItems WHERE __key__ in :1’, saveditemkeys)