Query Datastore

Nota: gli sviluppatori che creano nuove applicazioni sono vivamente invitati a utilizzare la libreria client NDB, che offre diversi vantaggi rispetto a questa libreria client, ad esempio la memorizzazione nella cache automatica delle entità tramite l'API Memcache. Se al momento utilizzi la libreria client DB precedente, leggi il Guida alla migrazione da DB a NDB

Una query di Datastore recupera entità da Cloud Datastore che soddisfano un insieme specificato di condizioni.

Una query tipica include quanto segue:

  • Un tipo di entità a cui si applica la query
  • Filtri facoltativi basati su valori, chiavi e antenati delle proprietà delle entità
  • Ordini facoltativi per sequenziare i risultati
Quando viene eseguita, una query recupera tutte le entità del tipo specificato che soddisfano tutti i filtri specificati, ordinati nell'ordine specificato. Le query vengono eseguite come di sola lettura.

Questa pagina descrive la struttura e i tipi di query utilizzati in App Engine per per recuperare i dati da Cloud Datastore.

Filtri

I filtri di una query impostano vincoli sulle proprietà, sulle chiavi e sugli antenati delle entità da recuperare.

Filtri proprietà

Un filtro proprietà specifica

  • Un nome di proprietà
  • Un operatore di confronto
  • Valore di una proprietà
Ad esempio:

q = Person.all()
q.filter("height <=", max_height)

Il valore della proprietà deve essere fornito dall'applicazione. a cui non può fare riferimento calcolato in termini di altre proprietà. Un'entità soddisfa il filtro se ha una proprietà del nome specificato il cui valore è confrontato con quello specificato il filtro nel modo descritto dall'operatore di confronto.

L'operatore di confronto può essere uno dei seguenti:

Operatore Significato
= Uguale a
< Minore di
<= Minore o uguale a
> Maggiore di
>= Maggiore o uguale a
!= Diverso da
IN Componente di (uguale a uno qualsiasi dei valori in un elenco specificato)

La non uguale (!=) esegue due query: una in cui tutti gli altri filtri vengono senza modifiche non uguale viene sostituito da un minore di (<) e uno in cui è sostituito da un maggiore di (>) filtro. I risultati vengono poi uniti in ordine. Una query può avere al massimo non uguale e una query con uno non può avere altri filtri di disuguaglianza.

L'operatore IN esegue anche query: una per ogni elemento nell'elenco specificato, con tutti gli altri filtri non modificato e il filtro IN è stato sostituito con uguaglianza (=) filtro. I risultati vengono uniti in base all'ordine degli elementi nell'elenco. Se una query ha più di un filtro IN, viene eseguito più query, una per ogni possibile combinazione di valori IN elenchi.

Una singola query contenente non uguale (!=) o IN è limitato a un massimo di 30 sottoquery.

Filtri principali

Per filtrare in base al valore della chiave di un'entità, utilizza la proprietà speciale __key__:

q = Person.all()
q.filter('__key__ >', last_seen_key)

Quando si esegue il confronto per verificare l'ineguaglianza, le chiavi vengono ordinate in base ai seguenti criteri:

  1. Percorso dell'antenato
  2. Tipo di entità
  3. Identificatore (nome della chiave o ID numerico)

Gli elementi del percorso predecessore vengono confrontati in modo simile: per tipo (stringa), per nome della chiave o ID numerico. Tipi e nomi di chiavi sono stringhe e sono ordinati per valore byte; Gli ID numerici sono numeri interi e sono ordinati numericamente. Se le entità con gli stessi valori padre e tipo utilizzano una combinazione di stringhe di nomi chiave e ID numerici, quelli con ID numerici precedono quelli con i nomi delle chiavi.

Le query sulle chiavi utilizzano gli indici esattamente come le query sulle proprietà e richiedono indici personalizzati negli stessi casi, con un paio di eccezioni: i filtri o un ordinamento crescente sulla chiave non richiedono un indice personalizzato, un ordinamento decrescente sulla chiave. Come per tutte le query, il server web di sviluppo crea voci appropriate nel file di configurazione dell'indice quando viene testata una query che richiede un indice personalizzato.

Filtri predecessori

Puoi filtrare le query Datastore in base a un predecessore specificato, in modo che i risultati restituiti includano solo le entità discendenti da tale predecessore:

q = Person.all()
q.ancestor(ancestor_key)

Tipi di query speciali

Alcuni tipi specifici di query meritano una menzione speciale:

Query gentili

Una query senza tipo e senza filtro di antenato recupera tutte le entità di un'applicazione da Datastore. Sono incluse le entità create e gestite da altre funzionalità di App Engine, come entità statistiche ed entità metadati Blobstore (se presenti). Queste query senza tipo non possono includere filtri o ordini di ordinamento in base ai valori delle proprietà. Tuttavia, possono filtrare in base alle chiavi delle entità specificando __key__ come nome della proprietà:

q = db.Query()
q.filter('__key__ >', last_seen_key)

In Python, ogni entità restituita dalla query deve avere una classe modello corrispondente definita per il tipo di entità. Per definire le classi di modelli per i tipi di entità statistiche, devi importare il pacchetto stats:

from google.appengine.ext.db import stats

Se la tua applicazione ha un valore Blobstore, devi aggiungere il seguente codice per fare in modo che l'API di query riconosca il tipo di entità __BlobInfo__. L'importazione dell'API Blobstore non definisce questa classe.

from google.appengine.ext import db

class BlobInfo(db.Expando):
  @classmethod
  def kind(cls):
    return '__BlobInfo__'

Query sui predecessori

Una query con un filtro predecessore limita i risultati all'entità specificata e ai suoi discendenti:

tom = Person(key_name='Tom')

wedding_photo = Photo(parent=tom)
wedding_photo.image_url='http://domain.com/some/path/to/wedding_photo.jpg'
wedding_photo.put()

baby_photo = Photo(parent=tom)
baby_photo.image_url='http://domain.com/some/path/to/baby_photo.jpg'
baby_photo.put()

dance_photo = Photo(parent=tom)
dance_photo.image_url='http://domain.com/some/path/to/dance_photo.jpg'
dance_photo.put()

camping_photo = Photo()
camping_photo.image_url='http://domain.com/some/path/to/camping_photo.jpg'
camping_photo.put()


photo_query = Photo.all()
photo_query.ancestor(tom)


# This returns wedding_photo, baby_photo, and dance_photo,
# but not camping_photo, because tom is not an ancestor
for photo in photo_query.run(limit=5):
  # Do something with photo

Query da predecessore senza tipo

Una query senza tipo che include un filtro predecessore recupererà predecessore e tutti i suoi discendenti, indipendentemente dal tipo. Questo tipo di query non richiedono indici personalizzati. Come tutte le query senza tipo, non può includere filtri o ordini di ordinamento in base ai valori delle proprietà, ma può filtrare in base alla chiave dell'entità:

q = db.Query()
q.ancestor(ancestor_key)
q.filter('__key__ >', last_seen_key)

Per eseguire una query predecessore senza tipo mediante GQL (nella console di amministrazione di App Engine o utilizzando la classe GqlQuery), ometti la clausola FROM:

q = db.GqlQuery('SELECT * WHERE ANCESTOR IS :1 AND __key__ > :2',
                ancestor_key,
                last_seen_key)

L'esempio seguente illustra come recuperare tutte le entità discendenti da un determinato antenato:

tom = Person(key_name='Tom')

wedding_photo = Photo(parent=tom)
wedding_photo.image_url='http://domain.com/some/path/to/wedding_photo.jpg'
wedding_photo.put()

wedding_video = Video(parent=tom)
wedding_video.video_url='http://domain.com/some/path/to/wedding_video.avi'
wedding_video.put()

# The following query returns both weddingPhoto and weddingVideo,
# even though they are of different entity kinds
media_query = db.query_descendants(tom)
for media in media_query.run(limit=5):
  # Do something with media

Query basate solo su chiavi

Una query basata solo su chiavi restituisce solo le chiavi delle entità di risultato anziché le entità stesse, con una latenza e un costo inferiori rispetto al recupero di entità intere:

q = Person.all(keys_only=True)

Spesso è più economico eseguire prima una query solo per le chiavi e poi recuperare un sottoinsieme di entità dai risultati, anziché eseguire una query generale che potrebbe recuperare più entità di quelle di cui hai bisogno.

Query di proiezione

A volte tutto ciò di cui hai davvero bisogno dai risultati di una query sono i valori di un alcune proprietà specifiche. In questi casi, puoi utilizzare una query di proiezione per recuperare solo le proprietà che ti interessano effettivamente, con una latenza e un costo inferiori rispetto al recupero dell'intera entità. Per maggiori dettagli, consulta la pagina Query di proiezione.

Ordinare gli ordini

Un ordinamento di query specifica

  • Un nome di proprietà
  • Una direzione di ordinamento (crescente o decrescente)

In Python, l'ordinamento decrescente è indicato da un trattino (-) precedente il nome della proprietà. Se ometti il trattino, viene specificato l'ordinamento crescente per impostazione predefinita. Ad esempio:

# Order alphabetically by last name:
q = Person.all()
q.order('last_name')

# Order by height, tallest to shortest:
q = Person.all()
q.order('-height')

Se una query include più ordinamenti, questi vengono applicati nella sequenza specificato. Nell'esempio seguente viene ordinato prima in base al cognome in ordine crescente e poi per altezza decrescente:

q = Person.all()
q.order('lastName')
q.order('-height')

Se non vengono specificati ordini di ordinamento, i risultati vengono restituiti nell'ordine in cui vengono recuperati da Datastore.

Nota: per via del modo Datastore esegue le query, se una query specifica filtri di disuguaglianza su una proprietà e ordina le altre, la proprietà utilizzata nella I filtri di disuguaglianze devono essere ordinati prima delle altre proprietà.

Indici

Ogni query Datastore calcola i risultati utilizzando uno o più indici contenenti chiavi di entità in una sequenza specificata dalle proprietà dell'indice e, facoltativamente, i predecessori dell'entità. Gli indici vengono aggiornati in modo incrementale per riflettere qualsiasi modifica apportata dall'applicazione alle sue entità, in modo che i risultati corretti di tutte le query siano disponibili senza ulteriori calcoli necessaria.

App Engine predefinisce un indice semplice per ogni proprietà di un'entità. Un'applicazione App Engine può definire ulteriori indici personalizzati in un indice di configurazione del deployment denominato index.yaml. Il server di sviluppo esegue automaticamente aggiunge suggerimenti a questo file quando rileva query che non possono essere eseguite con gli indici esistenti. Puoi ottimizzare manualmente gli indici modificando il file prima di caricare l'applicazione.

Esempio di interfaccia di query

L'API Datastore per Python fornisce due classi per preparare ed eseguire le query:

  • Query utilizza le chiamate al metodo per preparare la query.
  • GqlQuery utilizza un linguaggio di query di tipo SQL, denominato GQL, per preparare la query da una stringa di query.
class Person(db.Model):
  first_name = db.StringProperty()
  last_name = db.StringProperty()
  city = db.StringProperty()
  birth_year = db.IntegerProperty()
  height = db.IntegerProperty()


# Query interface constructs a query using instance methods
q = Person.all()
q.filter("last_name =", "Smith")
q.filter("height <=", max_height)
q.order("-height")


# GqlQuery interface constructs a query using a GQL query string
q = db.GqlQuery("SELECT * FROM Person " +
                "WHERE last_name = :1 AND height <= :2 " +
                "ORDER BY height DESC",
                "Smith", max_height)


# Query is not executed until results are accessed
for p in q.run(limit=5):
  print "%s %s, %d inches tall" % (p.first_name, p.last_name, p.height)

Passaggi successivi