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 no Java 8

Para criar uma consulta de projeção, crie um objeto Query e adicione propriedades a ele usando o método addProjection():

private void addGuestbookProjections(Query query) {
  query.addProjection(new PropertyProjection("content", String.class));
  query.addProjection(new PropertyProjection("date", Date.class));
}

O tipo especificado para cada propriedade precisa corresponder ao que você usou quando definiu a propriedade pela primeira vez usando Entity.setProperty(). O exemplo a seguir mostra como processar os resultados da consulta iterando a lista de entidades retornadas e fazendo o cast de todos os valores de propriedade para o tipo esperado:

private void printGuestbookEntries(DatastoreService datastore, Query query, PrintWriter out) {
  List<Entity> guests = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(5));
  for (Entity guest : guests) {
    String content = (String) guest.getProperty("content");
    Date stamp = (Date) guest.getProperty("date");
    out.printf("Message %s posted on %s.\n", content, stamp.toString());
  }
}

Agrupamento(experimental)

As consultas de projeção podem usar o método setDistinct() 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.

Query q = new Query("TestKind");
q.addProjection(new PropertyProjection("A", String.class));
q.addProjection(new PropertyProjection("B", Long.class));
q.setDistinct(true);
q.setFilter(Query.FilterOperator.LESS_THAN.of("B", 1L));
q.addSort("B", Query.SortDirection.DESCENDING);
q.addSort("A");

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 (EQUAL) 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 mostrados em uma consulta de projeção não podem ser salvos no Datastore.

    Como a consulta só retorna resultados parcialmente preenchidos, você não precisa regravá-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, datastore-indexes-auto.xml, 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.