Query di proiezione

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

Le query di proiezione sono simili alle query SQL nel formato:

SELECT name, email, phone FROM CUSTOMER

Puoi utilizzare tutte le funzionalità di filtro e ordinamento disponibili per le query di entità standard, fatte salve le limitazioni descritte di seguito. La query restituisce risultati ridotti in cui solo le proprietà specificate (name, email e phone nell'esempio) sono state compilate con i valori; tutte le altre proprietà non contengono dati.

Utilizzo delle query di proiezione in Python 2

Considera il seguente modello:

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

Puoi specificare una proiezione nel seguente modo:

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

Puoi gestire i risultati di queste query come faresti per una query di entità standard, ad esempio eseguendo l'iterazione dei risultati.

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

Puoi prevedere 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 garantire che in un set 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à di cui si esegue la previsione.

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 ciascun autore una sola volta.

Limitazioni sulle proiezioni

Le query di proiezione sono soggette alle seguenti limitazioni:

  • È possibile prevedere solo le proprietà indicizzate.

    La proiezione non è supportata per le proprietà non indicizzate, in modo esplicito o implicito. Le stringhe di testo lunghe (Text) e le stringhe di byte lunghi (Blob) non vengono indicizzate.

  • Non è possibile prevedere la stessa proprietà più di una volta.

  • Non è possibile prevedere le proprietà a cui viene fatto riferimento in un filtro di uguaglianza (=) o di appartenenza (IN).

    Ad esempio:

    SELECT A FROM kind WHERE B = 1
    

    è valida (proprietà prevista non utilizzata nel filtro di uguaglianza), così com'è

    SELECT A FROM kind WHERE A > 1
    

    (non un filtro di uguaglianza), ma

    SELECT A FROM kind WHERE A = 1
    

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

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

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

Proiezioni e proprietà a più valori

La proiezione di una proprietà con più valori non completerà tutti i valori per quella proprietà. Verrà invece restituita un'entità separata per ogni combinazione univoca di valori previsti corrispondenti alla query. Ad esempio, supponi di avere un'entità di tipo Foo con due proprietà a più valori, A e B:

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

Quindi 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à a più valori senza valori, non verranno incluse voci nell'indice e non verranno restituiti risultati per quell'entità da una query di proiezione che include quella 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 degli indici, 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 quando non sono sempre necessarie. Ad esempio, queste query richiedono due indici distinti:

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

Tuttavia, se progetti 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à della 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)

Conversione 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 quindi richiederà la creazione di un nuovo indice Index(Kind, A, B, C). Nota che la query di proiezione

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

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