Consultas de projeção

Na maioria das consultas do Datastore, entidades inteiras são retornadas como resultados, mas, normalmente, apenas algumas propriedades delas são relevantes para o aplicativo. As consultas de projeção permitem que você consulte no Datastore apenas as propriedades específicas que você realmente precisa em uma entidade, com latência e custo menores do que a recuperação de entidades inteiras.

As consultas de projeção são semelhantes às de SQL do formulário:

SELECT name, email, phone FROM CUSTOMER

É possível usar todos os recursos de filtragem e classificação disponíveis para consultas de entidade padrão, sujeitos às limitações descritas abaixo. A consulta retorna resultados resumidos apenas com as propriedades especificadas (name, email e phone, no exemplo) preenchidas com valores. Todas as outras propriedades não têm dados.

Como usar consultas de projeção em Python 2

Considere o seguinte modelo:

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

Especifique uma projeção desta forma:

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

A forma de tratar os resultados dessas consultas é a mesma para a consulta de entidade padrão. Por exemplo, iterando os resultados.

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

É possível projetar sub-propriedades indexadas a partir de uma propriedade estruturada. Para conseguir apenas a propriedade city da propriedade estruturada address de um contato, use uma projeção como:

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])

Agrupamento(experimental)

As consultas de projeção podem usar a palavra-chave distinct para garantir que apenas resultados totalmente exclusivos sejam retornados em um conjunto de resultados. Isso retornará apenas o primeiro resultado de entidades com os mesmos valores das propriedades projetadas.

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

Ambas as consultas são equivalentes e produzirão o nome de cada autor apenas uma vez.

Limitações nas projeções

As consultas de projeção estão sujeitas às seguintes limitações:

  • Somente propriedades indexadas podem ser projetadas.

    A projeção não é compatível com propriedades não indexadas, seja de maneira explícita ou implícita. Strings de texto longas (Text) e strings de bytes longas (Blob) não são indexadas.

  • A mesma propriedade não pode ser projetada mais de uma vez.

  • Propriedades referenciadas em um filtro de igualdade (=) ou de associação (IN) não são projetadas.

    Por exemplo,

    SELECT A FROM kind WHERE B = 1
    

    é uma consulta válida (a propriedade projetada não é usada no filtro de igualdade), assim como a consulta

    SELECT A FROM kind WHERE A > 1
    

    (não é um filtro de igualdade), mas

    SELECT A FROM kind WHERE A = 1
    

    (propriedade projetada usada no filtro de igualdade) não é.

  • Os resultados retornados por uma consulta de projeção não podem ser salvos no Datastore.

    Como a consulta retorna resultados parcialmente preenchidos, não é possível gravá-los no Datastore.

Projeções e propriedades de vários valores

A projeção de uma propriedade de vários valores não preencherá todos os valores dessa propriedade. Em vez disso, uma entidade separada será retornada para cada combinação exclusiva de valores projetados correspondentes à consulta. Por exemplo, suponha que você tenha uma entidade do tipo Foo com duas propriedades de múltiplos valores, A e B:

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

Neste caso, a consulta de projeção

SELECT A, B FROM Foo WHERE A < 3

retornará quatro entidades com as seguintes combinações de valores:

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

Observe que, se uma entidade tiver uma propriedade de vários valores sem valores, nenhuma entrada será incluída no índice, e nenhum resultado para essa entidade será retornado de uma consulta de projeção que inclua essa propriedade.

Índices de projeções

Consultas de projeção exigem que todas as propriedades especificadas estejam incluídas em um índice do Datastore. O servidor de desenvolvimento do App Engine gera automaticamente os índices necessários no arquivo de configuração do índice, index.yaml, que é carregado com o aplicativo.

Uma forma de reduzir o número de índices necessários é projetar as mesmas propriedades consistentemente, mesmo quando nem todas são necessárias. Por exemplo, essas consultas exigem dois índices separados:

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

No entanto, se você projetar sempre as propriedades A, B e C, mesmo se C não for obrigatória, apenas um índice será necessário.

A conversão de uma consulta em uma projeção talvez exija a criação de um novo índice caso as propriedades dessa projeção não estejam em outra parte da consulta. Por exemplo, suponhamos que você tenha uma consulta como:

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

que exija o índice

Index(Kind, A, B)

A conversão em uma das consultas de projeção

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

introduz uma nova propriedade (C), sendo, portanto, necessário criar um novo índice Index(Kind, A, B, C). A consulta de projeção

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

não altera o índice exigido, uma vez que as propriedades projetadas A e B já foram incluídas na consulta existente.