Query di progetto

La maggior parte delle query di Datastore restituisce intere entità come risultati, ma spesso un'applicazione è effettivamente interessata solo a poche proprietà dell'entità. Le query di proiezione ti consentono di eseguire query su Datastore solo per le proprietà specifiche di un'entità di cui hai effettivamente bisogno, a una latenza e un costo inferiori rispetto al recupero dell'intera entità.

Le query di proiezione sono simili alle query SQL del seguente tipo:

SELECT name, email, phone FROM CUSTOMER

Puoi utilizzare tutte le funzionalità di filtro e ordinamento disponibili per le query sulle entità standard, rispettando le limitazioni descritte di seguito. La query restituisce risultati abbreviati con solo le proprietà specificate (name, email e phone nell'esempio) con valori inseriti; tutte le altre proprietà non hanno dati.

Utilizzo delle query di proiezione

Considera il seguente modello:

class Article(ndb.Model):
    title = ndb.StringProperty()
    author = ndb.StringProperty()
    tags = ndb.StringProperty(repeated=True)

Per specificare una proiezione:

def print_author_tags():
    query = Article.query()
    articles = query.fetch(20, projection=[Article.author, Article.tags])
    for article in articles:
        print(article.author)
        print(article.tags)
        # article.title will raise a ndb.UnprojectedPropertyError

Gestisci i risultati di queste query come faresti per una query sulle entità standard: ad esempio, iterando sui risultati.

for article in articles:
        print(article.author)
        print(article.tags)
        # article.title will raise a ndb.UnprojectedPropertyError

Puoi proiettare proprietà secondarie indicizzate da una proprietà strutturata. Per ottenere solo la proprietà city della proprietà strutturata address di un contatto, puoi utilizzare una proiezione come:

class Address(ndb.Model):
    type = ndb.StringProperty()  # E.g., 'home', 'work'
    street = ndb.StringProperty()
    city = ndb.StringProperty()
...
class Contact(ndb.Model):
    name = ndb.StringProperty()
    addresses = ndb.StructuredProperty(Address, repeated=True)
...
Contact.query().fetch(projection=["name", "addresses.city"])
Contact.query().fetch(projection=[Contact.name, Contact.addresses.city])

Raggruppamento(sperimentale)

Le query di proiezione possono utilizzare la parola chiave distinct per assicurarsi che in un insieme di risultati vengano restituiti solo risultati completamente unici. Verrà restituito solo il primo risultato per le entità che hanno gli stessi valori per le proprietà che vengono proiettate.

Article.query(projection=[Article.author], group_by=[Article.author])
Article.query(projection=[Article.author], distinct=True)

Entrambe le query sono equivalenti e produrranno il nome di ogni autore una sola volta.

Limitazioni delle proiezioni

Le query di proiezione sono soggette alle seguenti limitazioni:

  • Possono essere proiettate solo le proprietà indicizzate.

    La proiezione non è supportata per le proprietà non indicizzate, esplicitamente o implicitamente. Le stringhe di testo lunghe (Text) e le stringhe di byte lunghe (Blob) non sono indicizzate.

  • La stessa proprietà non può essere proiettata più di una volta.

  • Le proprietà a cui viene fatto riferimento in un filtro di uguaglianza (=) o di appartenenza (IN) non possono essere proiettate.

    Ad esempio,

    SELECT A FROM kind WHERE B = 1
    

    sia valida (proprietà proiettata non utilizzata nel filtro di uguaglianza), sia

    SELECT A FROM kind WHERE A > 1
    

    (non è un filtro di uguaglianza), ma

    SELECT A FROM kind WHERE A = 1
    

    (proprietà proiettata utilizzata nel filtro di uguaglianza) non lo è.

  • I risultati restituiti da una query di proiezione non possono essere salvati di nuovo in Datastore.

    Poiché la query restituisce risultati compilati solo parzialmente, non puoi riscriverli in Datastore.

Proiezioni e proprietà con più valori

La proiezione di una proprietà con più valori non comporterà l'inserimento di tutti i valori per quella proprietà. Verrà restituita un'entità separata per ogni combinazione unica di valori proiettati corrispondenti alla query. Ad esempio, supponiamo di avere un'entità di tipo Foo con due proprietà con più valori, A e B:

entity = Foo(A=[1, 1, 2, 3], B=['x', 'y', 'x'])

Poi la query di proiezione

SELECT A, B FROM Foo WHERE A < 3

restituirà quattro entità con le seguenti combinazioni di valori:

A = 1, B = 'x'
A = 1, B = 'y'
A = 2, B = 'x'
A = 2, B = 'y'

Tieni presente che se un'entità ha una proprietà con più valori senza valori, nell'indice non verranno incluse voci e non verranno restituiti risultati per l'entità da una query di proiezione che include la proprietà.

Indici per le proiezioni

Le query di proiezione richiedono che tutte le proprietà specificate nella proiezione siano incluse in un indice Datastore. Il server di sviluppo App Engine genera automaticamente gli indici necessari nel file di configurazione dell'indice, index.yaml, che viene caricato con l'applicazione.

Un modo per ridurre al minimo il numero di indici richiesti è proiettare le stesse proprietà in modo coerente, anche se non tutte sono sempre necessarie. Ad esempio, queste query richiedono due indici distinti:

SELECT A, B FROM Kind
SELECT A, B, C FROM Kind

Tuttavia, se proietti sempre le proprietà A, B e C, anche quando C non è obbligatorio, sarà necessario un solo indice.

La conversione di una query esistente in una query di proiezione potrebbe richiedere la creazione di un nuovo indice se le proprietà nella proiezione non sono già incluse in un'altra parte della query. Ad esempio, supponiamo che tu abbia una query esistente come

SELECT * FROM Kind WHERE A > 1 ORDER BY A, B

che richiede l'indice

Index(Kind, A, B)

Convertendo questo valore in una delle query di proiezione

SELECT C FROM Kind WHERE A > 1 ORDER BY A, B
SELECT A, B, C FROM Kind WHERE A > 1 ORDER BY A, B

introduce una nuova proprietà (C) e, di conseguenza, richiede la creazione di un nuovo indice Index(Kind, A, B, C). Tieni presente che la query di proiezione

SELECT A, B FROM Kind WHERE A > 1 ORDER BY A, B

non cambierebbe l'indice richiesto, poiché le proprietà proiettate A e B erano già incluse nella query esistente.