Observação: é altamente recomendável a desenvolvedores que criam novos aplicativos usar a biblioteca de cliente NDB, porque ela oferece diversos benefícios em comparação com esta biblioteca de cliente, como armazenamento em cache automático de entidades por meio da API Memcache. Se você estiver usando a antiga biblioteca de cliente DB, leia o Guia de migração de DB para NDB.
Uma consulta do Datastore recupera entidades do Cloud Datastore que atendem a um conjunto específico de condições.
Uma consulta típica inclui:
- um tipo de entidade a que a consulta se aplica;
- filtros opcionais que têm como base os valores de propriedade, as chaves e os ancestrais das entidades;
- ordens de classificação opcionais para sequenciar os resultados.
Nesta página, descrevemos a estrutura e tipos de consultas usadas no App Engine para recuperar dados do Cloud Datastore.
Filtros
O conjunto de filtros de uma consulta restringe as propriedades, chaves e ancestrais das entidades que serão recuperadas.
Filtros de propriedade
Um filtro de propriedade especifica:
- um nome de propriedade;
- um operador de comparação;
- um valor de propriedade.
q = Person.all() q.filter("height <=", max_height)
O valor da propriedade deve ser fornecido pelo aplicativo. Ele não pode referir-se a outras propriedades nem ser calculado em relação a elas. Uma entidade satisfaz ao filtro se tiver uma propriedade com o nome determinado com valor igual ao especificado no filtro, da maneira descrita pelo operador de comparação.
O operador de comparação pode ser qualquer um destes:
Operador | Significado |
---|---|
= |
Igual a |
< |
Menor que |
<= |
Menor que ou igual a |
> |
Maior que |
>= |
Maior que ou igual a |
!= |
Diferente de |
IN |
Membro de (igual a qualquer um dos valores em uma lista especificada) |
O
operador "diferente de"
(!=
) realiza duas consultas: uma em que todos os outros filtros
permanecem inalterados e
o filtro "diferente de" é
substituído por um filtro
"menor que" (<
) e
outro em que é substituído por um filtro
"maior que"
(>
). Em seguida, os resultados são mesclados na ordem. Uma consulta não pode ter mais que um filtro "diferente de", e uma consulta que tenha um filtro de desigualdade não pode ter outros desse tipo.
O operador IN
também executa várias consultas: uma para cada item na lista especificada, com todos os outros filtros inalterados e o filtro IN
substituído por um filtro de igualdade (=
). Os resultados são mesclados na ordem dos itens na lista. Se uma consulta
tiver mais que um filtro IN
, ela será
executada como várias consultas, uma para cada combinação possível de
valores nas listas IN
.
Uma única consulta contendo os operadores
"diferente de" !=
ou IN
é limitada a no máximo 30 subconsultas.
Filtros de chave
Para filtrar o valor da chave de uma entidade, use a propriedade especial __key__
.
q = Person.all()
q.filter('__key__ >', last_seen_key)
Na comparação por desigualdade, as chaves são ordenadas pelos seguintes critérios, nesta ordem:
- Caminho do ancestral
- Tipo de entidade
- Identificador (nome da chave ou ID numérico)
Os elementos do caminho ancestral são comparados de forma análoga: por tipo (string) e, em seguida, por nome de chave ou ID numérico. Os tipos e nomes de chave são strings e estão ordenados por valor de bytes. Os IDs numéricos são representados em números inteiros e ordenados numericamente. Se entidades com o mesmo pai e do mesmo tipo usarem uma combinação de strings de nomes de chave e IDs numéricos, aquelas com códigos numéricos precederão as entidades com nomes de chave.
As consultas por chaves usam índices da mesma maneira que as consultas por propriedades e exigem índices personalizados nos mesmos casos. Porém, há algumas exceções: filtros de desigualdade ou uma ordem de classificação crescente na chave não exigem um índice personalizado, mas uma ordem de classificação decrescente na chave, sim. Como em todas as consultas, o servidor da Web de desenvolvimento cria as entradas adequadas no arquivo de configuração de índices quando uma consulta que precisa de um índice personalizado é testada.
Filtros de ancestrais
É possível filtrar as consultas do Datastore de acordo com um ancestral especificado para que os resultados retornados incluam apenas entidades descendentes desse ancestral:
q = Person.all()
q.ancestor(ancestor_key)
Tipos de consulta especiais
Alguns tipos específicos de consulta merecem uma menção especial:
Consultas sem tipo
Uma consulta sem tipo e sem nenhum filtro ancestral recupera todas as entidades de um aplicativo do Datastore. Isso inclui entidades criadas e gerenciadas por outros recursos do App Engine, como entidades de estatísticas e entidades de metadados do Blobstore (se houver). Essas consultas sem tipo não podem incluir filtros ou ordens de classificação para valores de propriedade. Eles podem, no entanto, filtrar chaves de entidade especificando __key__
como o nome da propriedade:
q = db.Query()
q.filter('__key__ >', last_seen_key)
No Python, toda entidade retornada pela consulta precisa ter uma classe de modelo correspondente definida para o tipo da entidade. Para definir as classes de modelo para os tipos de estatísticas da entidade, importe o pacote stats
:
from google.appengine.ext.db import stats
Se o aplicativo tiver um valor do Blobstore, adicione o código a seguir para que a API de consulta reconheça o tipo de entidade __BlobInfo__
. Importar a Blobstore API não define essa classe.
from google.appengine.ext import db
class BlobInfo(db.Expando):
@classmethod
def kind(cls):
return '__BlobInfo__'
Consultas de ancestral
Uma consulta com um filtro ancestral limita os resultados à entidade especificada e seus descendentes:
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)
# This returns wedding_photo, baby_photo, and dance_photo,
# but not camping_photo, because tom is not an ancestor
for photo in photo_query.run(limit=5):
# Do something with photo
Consultas de ancestral sem tipo
Uma consulta sem tipo que inclui um filtro ancestral recuperará o ancestral especificado e todos os descendentes dele, independentemente do tipo. Esse tipo de consulta não requer índices personalizados. Como todas as consultas sem tipo, ela não inclui filtros ou ordens de classificação em valores de propriedade, mas pode filtrar a chave da entidade:
q = db.Query()
q.ancestor(ancestor_key)
q.filter('__key__ >', last_seen_key)
Para executar uma consulta de ancestral sem tipo usando o GQL (no Console de administração do App Engine ou usando a classe GqlQuery
), omita a cláusula FROM
:
q = db.GqlQuery('SELECT * WHERE ANCESTOR IS :1 AND __key__ > :2',
ancestor_key,
last_seen_key)
O exemplo a seguir mostra como recuperar todas as entidades descendentes de um determinado ancestral:
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()
# The following query returns both weddingPhoto and weddingVideo,
# even though they are of different entity kinds
media_query = db.query_descendants(tom)
for media in media_query.run(limit=5):
# Do something with media
Consultas apenas de chaves
Uma consulta apenas de chaves retorna somente as chaves das entidades resultantes em vez das próprias entidades, o que resulta em menor latência e custo do que a recuperação de entidades inteiras:
q = Person.all(keys_only=True)
Muitas vezes, é mais econômico fazer uma consulta apenas de chaves primeiro e, em seguida, buscar um subconjunto de entidades nos resultados em vez de executar uma consulta geral, que pode buscar mais entidades do que você realmente precisa.
Consultas de projeção
Às vezes a única coisa de que você precisa dos resultados de uma consulta são os valores de algumas propriedades específicas. Nesses casos, é possível usar uma consulta de projeção para recuperar apenas as propriedades relevantes, com latência e custos menores do que recuperar toda a entidade. Para mais detalhes, acesse a página Consultas de projeção.
Ordens de classificação
A ordem de classificação de uma consulta específica:
- um nome de propriedade;
- uma direção de classificação (crescente ou decrescente).
No Python, a ordem de classificação decrescente é indicada por um hífen
(-
) antes do nome da propriedade. Por padrão, a omissão do hífen especifica a
ordem crescente. Por exemplo:
# Order alphabetically by last name: q = Person.all() q.order('last_name') # Order by height, tallest to shortest: q = Person.all() q.order('-height')
Se uma consulta incluir várias ordens de classificação, elas serão aplicadas na sequência especificada. O exemplo a seguir classifica primeiro pelo sobrenome crescente e, em seguida, pela altura decrescente:
q = Person.all() q.order('lastName') q.order('-height')
Se nenhuma ordem de classificação for especificada, os resultados serão retornados na ordem em que forem recuperados do Datastore.
Observação: devido à maneira como o Datastore executa consultas, se uma consulta especificar filtros de desigualdade em uma propriedade e ordens de classificação em outras propriedades, a propriedade usada nos filtros de desigualdade precisará ser ordenada antes das outras propriedades.
Índices
Em todas as consultas do Datastore, os resultados são calculados com o uso de um ou mais índices, em que as chaves de entidade estão em uma sequência especificada pelas propriedades do índice ou pelos ancestrais da entidade. Os índices são atualizados para refletir as alterações feitas pelo aplicativo nas entidades. Assim, os resultados corretos de todas as consultas ficam disponíveis sem que seja preciso computar mais nada.
O App Engine predefine um índice simples em cada propriedade de uma entidade.
Um aplicativo do App Engine pode definir outros índices personalizados em um
arquivo de
configuração de índice chamado
index.yaml
. O servidor de desenvolvimento adiciona sugestões a esse arquivo automaticamente quando encontra consultas não executáveis com os índices atuais.
Você pode ajustar os índices manualmente editando o arquivo antes de fazer o upload do aplicativo.
Exemplo de interface de consulta
A Python Datastore API fornece duas classes para preparar e executar consultas:
Query
usa chamadas de método para preparar a consulta.GqlQuery
usa uma linguagem de consulta semelhante a SQL chamada GQL para preparar a consulta a partir de uma 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)
A seguir
- Saiba como especificar o que uma consulta retorna e ter mais controle sobre os resultados da consulta.
- Conheça as restrições comuns para consultas no Cloud Datastore.
- Saiba mais sobre os cursores de consulta, que permitem que um aplicativo recupere os resultados de uma consulta em lotes convenientes.
- Entenda a consistência dos dados e como ela funciona com diferentes tipos de consultas no Cloud Datastore.