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 Python 2

Considera el siguiente modelo:

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

Debes especificar una proyección de la siguiente manera:

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

Los resultados de estas consultas se controlan igual que los de una consulta de entidades estándar: por ejemplo, mediante la iteración sobre los resultados.

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

Puedes proyectar subpropiedades indexadas de una propiedad estructurada. Para obtener solo la propiedad city de la propiedad estructurada address de un contacto, puedes usar una proyección como la siguiente:

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

Agrupación(experimental)

Las consultas de proyección pueden usar la palabra clave distinct para garantizar que solo los resultados únicos en su totalidad se mostrarán en un conjunto de resultados. Esto solo mostrará el primer resultado de las entidades que tengan el mismo valor para las propiedades que se están proyectando.

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

Ambas consultas son equivalentes y producen solo una vez el nombre de cada autor.

Límites de 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 (=) 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 pueden volver a guardar en Datastore.

    Dado que la consulta muestra resultados que solo están propagados de manera parcial, estos no se pueden volver a escribir 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, index.yaml, 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.