Consultas de projeção

A maioria das consultas do Datastore devolve entidades inteiras como resultados, mas, muitas vezes, uma aplicação está realmente interessada apenas em algumas das propriedades da entidade. As consultas de projeção permitem-lhe consultar o Datastore apenas para as propriedades específicas de uma entidade de que realmente precisa, com uma latência e um custo inferiores aos da obtenção da entidade completa.

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

SELECT name, email, phone FROM CUSTOMER

Pode usar todas as funcionalidades de filtragem e ordenação disponíveis para consultas de entidades padrão, sujeitas às limitações descritas abaixo. A consulta devolve resultados reduzidos com apenas as propriedades especificadas (name, email e phone no exemplo) preenchidas com valores. Todas as outras propriedades não têm dados.

Usar consultas de projeção em Java 8

Para criar uma consulta de projeção, cria um objeto Query e adiciona-lhe propriedades através do método addProjection():

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

O tipo que especificar para cada propriedade tem de corresponder ao tipo que usou quando definiu inicialmente a propriedade com Entity.setProperty(). O exemplo seguinte mostra como processar os resultados da consulta iterando a lista de entidades devolvidas e convertendo cada valor de propriedade no 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 são devolvidos resultados totalmente únicos num conjunto de resultados. Isto só devolve o primeiro resultado para entidades que têm os mesmos valores para as propriedades que estão a ser 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:

  • Só é possível projetar propriedades indexadas.

    A projeção não é suportada para propriedades que não estão indexadas, quer de forma explícita ou implícita. As strings de texto longas (Text) e as strings de bytes longas (Blob) não são indexadas.

  • Não é possível projetar a mesma propriedade mais do que uma vez.

  • Não é possível projetar propriedades referenciadas num filtro de igualdade (EQUAL) ou de associação (IN).

    Por exemplo,

    SELECT A FROM kind WHERE B = 1
    

    É válido (a propriedade projetada não é usada no filtro de igualdade), tal como

    SELECT A FROM kind WHERE A > 1
    

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

    SELECT A FROM kind WHERE A = 1
    

    (projected property used in equality filter) is not.

  • Os resultados devolvidos por uma consulta de projeção não devem ser guardados novamente no Datastore.

    Uma vez que a consulta devolve resultados que estão apenas parcialmente preenchidos, não deve escrevê-los novamente no Datastore.

Projeções e propriedades com vários valores

A projeção de uma propriedade com vários valores não preenche todos os valores dessa propriedade. Em alternativa, é devolvida uma entidade separada para cada combinação única de valores projetados que corresponda à consulta. Por exemplo, suponhamos que tem uma entidade do tipo Foo com duas propriedades de vários valores, A e B:

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

Em seguida, a consulta de projeção

SELECT A, B FROM Foo WHERE A < 3

devolve 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'

Tenha em atenção que, se uma entidade tiver uma propriedade com vários valores sem valores, não são incluídas entradas no índice, e não são devolvidos resultados para essa entidade a partir de uma consulta de projeção que inclua essa propriedade.

Índices para projeções

As consultas de projeção requerem que todas as propriedades especificadas na projeção sejam incluídas num índice do Datastore. O servidor de desenvolvimento do App Engine gera automaticamente os índices necessários no ficheiro de configuração de índices, datastore-indexes-auto.xml, que é carregado com a sua aplicação.

Uma forma de minimizar o número de índices necessários é projetar as mesmas propriedades de forma consistente, mesmo quando nem todas são sempre necessárias. Por exemplo, estas consultas requerem dois índices separados:

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

No entanto, se projetar sempre as propriedades A, B e C, mesmo quando C não é obrigatório, só é necessário um índice.

A conversão de uma consulta existente numa consulta de projeção pode exigir a criação de um novo índice se as propriedades na projeção ainda não estiverem incluídas noutra parte da consulta. Por exemplo, suponha que tinha uma consulta existente como

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

que requer o índice

Index(Kind, A, B)

Converter isto numa 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) e, por isso, vai exigir a criação de um novo índice Index(Kind, A, B, C). Tenha em atenção que a consulta de projeção

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

não alteraria o índice necessário, uma vez que as propriedades projetadas A e B já estavam incluídas na consulta existente.