Python 2 ya no es compatible con la comunidad. Te recomendamos que migres las apps de Python 2 a Python 3.

Consultas de Datastore

Nota: Se recomienda enfáticamente a los desarrolladores que compilan aplicaciones nuevas que usen la biblioteca cliente de NDB, ya que tiene muchas ventajas en comparación con esta biblioteca cliente, como el almacenamiento en caché automático de entidades mediante la API de Memcache. Si por el momento usas la biblioteca cliente anterior de la base de datos, lee la Guía de migración de la base de datos a NDB.

Una consulta de Datastore recuperaentidades de Cloud Datastore que cumplan con un conjunto específico de condiciones.

Una consulta típica incluye lo siguiente:

Cuando se ejecuta, la consulta recupera todas las entidades del tipo determinado que satisfacen todos los filtros indicados, respetando el orden especificado. Las consultas se ejecutan en modo de solo lectura.

En esta página se describe la estructura y las categorías de consultas usadas dentro de App Engine para recuperar datos de Cloud Datastore.

Filtros

El conjunto de filtros de una consulta limita las propiedades, las claves y los principales de las entidades que se recuperarán.

Filtros de propiedades

Un filtro de propiedad especifica lo siguiente:

  • El nombre de una propiedad
  • Un operador de comparación
  • El valor de una propiedad
Por ejemplo:

q = Person.all()
q.filter("height <=", max_height)

La aplicación debe proporcionar el valor de la propiedad. No se puede referir ni calcular en términos de otras propiedades. Una entidad satisface el filtro si tiene una propiedad con el nombre dado, cuyo valor se compara con el valor especificado en el filtro, de acuerdo con la descripción del operador de comparación.

El operador de comparación puede ser cualquiera de las siguientes opciones:

Operador Significado
= Igual que
< Menor que
<= Menor que o igual que
> Mayor que
>= Mayor que o igual que
!= No igual que
IN Miembro de (igual a cualquier valor en una lista especificada)

En realidad, el operador de desigualdad (!=) realiza dos consultas: una en la que los demás filtros no se modifican y el filtro de desigualdad se reemplaza con un filtro menor que (<), y otra en la que se reemplaza con un filtro mayor que (>). Luego, los resultados se combinan en orden. Una consulta no puede tener más de un filtro no igual a y una consulta que tiene uno, no puede tener otros filtros de desigualdad.

El operador IN también realiza varias consultas: una para cada elemento de la lista especificada, con todos los demás filtros sin modificar y el filtro IN reemplazado con un filtro de paridad (=). Los resultados se combinan en el orden de los elementos en la lista. Si una consulta tiene más de un filtro IN, se realiza como consultas múltiples, una por cada combinación posible de los valores en las listas IN.

Una sola consulta que contenga operadores de desigualdad (!=) o IN está limitada a realizar no más de 30 subconsultas.

Filtros de clave

Para filtrar el valor de la clave de una entidad, usa la propiedad especial __key__:

q = Person.all() q.filter('__key__ >', last_seen_key)

Cuando se usa un comparador de desigualdad, se aplican los siguientes criterios para clasificar las claves, en orden:

  1. Ruta del principal
  2. Tipo de entidad
  3. Identificador (nombre de clave o ID numérico)

Los elementos de la ruta principal se comparan de manera similar: por tipo (string) y, luego, por nombre de clave o ID numérico. Los nombres de las claves y los tipos son strings y se ordenan por valor de byte. Los ID numéricos son números enteros y se ordenan numéricamente. Si varias entidades que tienen el mismo principal y tipo usan una combinación de ID numéricos y strings con nombre de clave, las entidades que tienen ID numéricos anteceden a las que tienen nombres de clave.

Las consultas sobre claves usan índices, al igual que las consultas sobre propiedades, y requieren índices personalizados en los mismos casos, salvo algunas excepciones: Cuando se usan filtros de desigualdad o un orden de clasificación ascendente en la clave, no se necesita un índice personalizado; cuando se usa un orden de clasificación descendente en la clave, sí. Al igual que con todas las consultas, el servidor de desarrollo crea entradas adecuadas en el archivo de configuración de índices cuando se prueba una consulta que requiere un índice personalizado.

Filtros principales

Puedes filtrar tus consultas de Datastore a un principal específico, de modo que los resultados que se muestren incluyan solo entidades que descienden de ese principal.

q = Person.all()q.ancestor(ancestor_key)

Tipos especiales de consultas

Hay algunos tipos específicos de consultas que merecen una mención especial:

Consultas sin categoría

Cuando una consulta no especifica el tipo ni el principal, se muestran todas las entidades de una aplicación del almacén de datos. Esto incluye entidades creadas y administradas por otras características de App Engine, como las entidades estadísticas y las entidades de metadatos de Blobstore (si las hubiera). Estas consultas sin categoría no pueden incluir filtros ni órdenes de clasificación en los valores de las propiedades. Sin embargo, pueden filtrar las claves de entidad especificando __key__ como el nombre de la propiedad:

q = db.Query() q.filter('__key__ >', last_seen_key)

En Python, cada entidad mostrada por la consulta debe tener una clase de modelo correspondiente definida para la categoría de la entidad. Si deseas definir las clases de modelo para las categorías de entidades de estadística, debes importar el paquete stats:

from google.appengine.ext.db import stats

Si tu aplicación tiene un valor de Blobstore, debes agregar el siguiente código para que la API de consulta reconozca el tipo de entidad __BlobInfo__. (Importar la API de Blobstore no define esta clase).

de google.appengine.ext import db clase BlobInfo(db.Expando): @classmethod def tipo(cls): muestra '__BlobInfo__'

Consultas principales

Una consulta con un filtro principal limita los resultados a la entidad especificada y a sus secundarios.

tom = Person(key_name='Tom') wedding_photo = Photo(parent=tom) wedding_photo.image_url='http://domain.com/some/path/to/wedding_photo.jpg' wedding_photo.put() baby_photo = Photo(parent=tom) baby_photo.image_url='http://domain.com/some/path/to/baby_photo.jpg' baby_photo.put() dance_photo = Photo(parent=tom) dance_photo.image_url='http://domain.com/some/path/to/dance_photo.jpg' dance_photo.put() camping_photo = Photo() camping_photo.image_url='http://domain.com/some/path/to/camping_photo.jpg' camping_photo.put() photo_query = Photo.all() photo_query.ancestor(tom) # Esto muestra wedding_photo, baby_photo, y dance_photo, # pero no camping_photo, porque tom no es un principal para la foto en photo_query.run(limit=5): # Hacer algo con la foto

Consultas principales sin categoría

Una consulta sin categoría que incluye un filtro principal recuperará el principal especificado y todos sus descendientes, sin importar la categoría. Este tipo de consulta no requiere índices personalizados. Al igual que todas las consultas sin categoría, no pueden incluir filtros ni órdenes de clasificación para los valores de propiedad, pero pueden filtrarse sobre la clave de la entidad.

q = db.Query() q.ancestor(ancestor_key) q.filter('__key__ >', last_seen_key)

Para realizar una consulta principal sin categoría mediante GQL (ya sea en la Consola del Administrador de App Engine o mediante la clase GqlQuery), debes omitir la cláusula FROM:

q = db.GqlQuery('SELECT * WHERE ANCESTOR IS :1 AND __key__ > :2', ancestor_key, last_seen_key)

El siguiente ejemplo muestra cómo recuperar todas las entidades descendientes de un principal dado:

tom = Person(key_name='Tom') wedding_photo = Photo(parent=tom) wedding_photo.image_url='http://domain.com/some/path/to/wedding_photo.jpg' wedding_photo.put() wedding_video = Video(parent=tom) wedding_video.video_url='http://domain.com/some/path/to/wedding_video.avi' wedding_video.put() # La siguiente consulta muestra weddingPhoto y weddingVideo, # aunque son dos tipos de entidades diferentes media_query = db.query_descendants(tom) de medios en media_query.run(limit=5): # Hacer algo con los medios

Consultas de solo clave

Una consulta de solo clave muestra solo las claves de las entidades resultantes, en lugar de las entidades en sí, con una latencia y un costo más bajos que recuperar entidades completas:

q = Person.all(keys_only=True)

A menudo, es más rentable hacer primero consultas de solo clave y, luego, recuperar un subconjunto de entidades de los resultados, en lugar de ejecutar una consulta general que puede arrojar más entidades que las que necesitas.

Consultas de proyección

En ocasiones, lo único que necesitas de los resultados de una consulta son los valores de unas pocas propiedades específicas. En estos casos, puedes usar una consulta de proyección para recuperar solo las propiedades que te interesan realmente, con costos y latencia menores que los de recuperar toda la entidad. Revisa la página sobre consultas de proyección para obtener más detalles.

Órdenes de clasificación

Un orden de clasificación de consulta especifica lo siguiente:

  • El nombre de una propiedad
  • Una dirección de clasificación (ascendente o descendente)

En Python, el orden de clasificación descendente se denota por medio de un guion (-) que precede al nombre de la propiedad; omitir el guion especifica un orden ascendente de forma predeterminada. Por ejemplo:

# Order alphabetically by last name:
q = Person.all()
q.order('last_name')

# Order by height, tallest to shortest:
q = Person.all()
q.order('-height')

Si una consulta incluye varios órdenes de clasificación, estos se aplican en la secuencia especificada. En el siguiente ejemplo, primero se clasifica por apellido ascendente, luego, por altura descendente:

q = Person.all()
q.order('lastName')
q.order('-height')

Si no se especifica ningún orden de clasificación, los resultados se muestran en el orden en que se recuperan de Datastore.

Nota: Debido a la forma en que Datastore ejecuta las consultas, si una consulta especifica filtros de desigualdad en una propiedad y órdenes de clasificación en otras propiedades, la propiedad que se use en los filtros de desigualdad deberá ordenarse antes de las demás propiedades.

Índices

Cada consulta de Datastore calcula los resultados mediante uno o más índices, que contienen claves de entidad en una secuencia especificada por las propiedades del índice y, de forma opcional, los principales de la entidad. Los índices se actualizan de forma incremental con los cambios que la aplicación haga a sus entidades, de modo que los resultados correctos de todas las consultas estén disponibles sin necesidad de realizar cálculos adicionales.

App Engine predefine un índice simple en cada propiedad de una entidad. Una aplicación de App Engine puede definir más índices personalizados en un archivo de configuración de índice llamado index.yaml. El servidor de desarrollo agrega sugerencias a este archivo automáticamente cuando encuentra consultas que no pueden ejecutarse con los índices existentes. Para ajustar los índices de manera manual, edita el archivo antes de subir la aplicación.

Ejemplo de interfaz de consulta

La API de Datastore de Python brinda dos clases para preparar y ejecutar consultas.

  • Query usa llamadas de método para preparar la consulta.
  • GqlQuery usa un lenguaje de consulta similar a SQL llamado GQL para preparar la consulta a partir de una string de consulta.

    class Person(db.Model):
      first_name = db.StringProperty()
      last_name = db.StringProperty()
      city = db.StringProperty()
      birth_year = db.IntegerProperty()
      height = db.IntegerProperty()
    
    # Query interface constructs a query using instance methods
    q = Person.all()
    q.filter("last_name =", "Smith")
    q.filter("height <=", max_height)
    q.order("-height")
    
    # GqlQuery interface constructs a query using a GQL query string
    q = db.GqlQuery("SELECT * FROM Person " +
                    "WHERE last_name = :1 AND height <= :2 " +
                    "ORDER BY height DESC",
                    "Smith", max_height)
    
    # Query is not executed until results are accessed
    for p in q.run(limit=5):
      print "%s %s, %d inches tall" % (p.first_name, p.last_name, p.height)
    

¿Qué sigue?