Consultas de proyección

La mayoría de las consultas de Datastore muestran entidades completas como resultado. Sin embargo, solo unas pocas propiedades de la entidad suelen ser relevantes para las aplicaciones. Las consultas de proyección te permiten hacer consultas en Datastore para aquellas propiedades específicas de una entidad que en verdad necesitas, con una latencia y un costo más bajos que si recuperas la entidad completa.

Las consultas de proyección son similares a las consultas de SQL que tienen la siguiente forma.

SELECT name, email, phone FROM CUSTOMER

Puedes usar todas las funciones de filtrado y clasificación disponibles para las consultas de entidades estándar, con las limitaciones que se describen a continuación. La consulta muestra resultados resumidos en los que solo se propagan las propiedades especificadas (name, email y phone en el ejemplo) con valores. Todas las demás propiedades no tienen datos.

Usa consultas de proyección en Java 8

Para compilar una consulta de proyección, debes crear un objeto Query y agregarle propiedades con el método addProjection():

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

El tipo que especifiques para cada propiedad debe coincidir con el tipo que usaste cuando definiste la propiedad por primera vez con Entity.setProperty(). En el siguiente ejemplo, se muestra cómo procesar los resultados de la consulta mediante la iteración a través de la lista de entidades mostrada y la conversión de cada valor de propiedad al 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());
  }
}

Agrupación(experimental)

Las consultas de proyección pueden usar el método setDistinct() para garantizar que solo se muestren en un conjunto de resultados los que sean únicos por completo. De este modo, solo se mostrará el primer resultado de las entidades que tengan los mismos valores para las propiedades que se están proyectando.

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");

Limitaciones para las proyecciones

Las consultas de proyección están sujetas a las limitaciones siguientes:

  • Solo se pueden proyectar propiedades indexadas.

    La proyección no admite propiedades que no estén indexadas, ya sea de forma explícita o implícita. Las strings de texto largas (Text) y las strings de bytes largas (Blob) no se indexan.

  • No se puede proyectar la misma propiedad más de una vez.

  • No se pueden proyectar las propiedades a las que se hizo referencia en un filtro de igualdad (EQUAL) o membresía (IN).

    Por ejemplo:

    SELECT A FROM kind WHERE B = 1
    

    Es una consulta válida, ya que la propiedad proyectada no se usa en el filtro de igualdad. También lo es la siguiente consulta:

    SELECT A FROM kind WHERE A > 1
    

    No es un filtro de igualdad. Sin embargo, la siguiente consulta no es válida:

    SELECT A FROM kind WHERE A = 1
    

    La propiedad proyectada se usa en un filtro de igualdad.

  • Los resultados que muestra una consulta de proyección no se deben volver a guardar en Datastore.

    Dado que la consulta muestra resultados que solo están propagados de forma parcial, estos no deben volver a escribirse en Datastore.

Proyecciones y propiedades con varios valores

La proyección de una propiedad con valores múltiples no propagará todos los valores para esa propiedad. En su lugar, se mostrará una entidad independiente para cada combinación única de valores proyectados que coincidan con la consulta. Por ejemplo, supón que tienes una entidad del tipo Foo con dos propiedades con valores múltiples, A y B:

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

Entonces, la consulta de proyección

SELECT A, B FROM Foo WHERE A < 3

mostrará cuatro entidades con las combinaciones de valores siguientes:

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

Ten en cuenta que, si una entidad tiene una propiedad de valores múltiples sin valores, no se incluirán entradas en el índice y no se mostrarán resultados para esa entidad a partir de una consulta de proyección que incluya esa propiedad.

Índices para proyecciones

Las consultas de proyección requieren que todas las propiedades especificadas en la proyección se incluyan en un índice de Datastore. El servidor de desarrollo de App Engine genera los índices necesarios de forma automática en el archivo de configuración de índices, datastore-indexes-auto.xml, que se sube junto con tu aplicación.

Una manera de minimizar el número de índices requeridos es proyectar las mismas propiedades de forma coherente, incluso si no las necesitas todas siempre. Por ejemplo, estas consultas requieren dos índices separados:

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

Sin embargo, si siempre proyectas las propiedades A, B y C, incluso si no necesitas C, solo necesitarás un índice.

Convertir una consulta existente en una consulta de proyección puede requerir que se cree un índice nuevo si las propiedades de la proyección no están incluidas en otra parte de la consulta. Por ejemplo, supón que tienes una consulta existente como esta:

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

que requiere el índice

Index(Kind, A, B)

Convertir esto en cualquiera de estas consultas de proyección

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

ingresa una nueva propiedad (C) y, por lo tanto, requerirá la creación de un nuevo índice Index(Kind, A, B, C). Ten en cuenta que la consulta de proyección

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

no cambiaría el índice requerido, debido a que las propiedades proyectadas A y B ya estaban incluidas en la consulta existente.