Entidades, propriedades e chaves

Observação: os desenvolvedores que criam novos aplicativos são bastante incentivados a usar a Biblioteca de cliente NDB, que 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 de DB, leia o Guia de migração de DB para NDB

Os objetos de dados no Cloud Datastore são conhecidos como entidades. Uma entidade tem uma ou mais propriedades nomeadas, que podem ter um ou mais valores. Entidades do mesmo tipo não precisam ter as mesmas propriedades. Além disso, os valores de uma entidade para uma determinada propriedade não precisam ser todos do mesmo tipo de dados. Se necessário, um aplicativo pode estabelecer e aplicar essas restrições no próprio modelo de dados.

O Cloud Datastore é compatível com uma grande variedade de tipos de dados para valores de propriedade. Eles incluem, entre outros:

  • Números inteiros
  • Números de ponto flutuante
  • Strings
  • Datas
  • Dados binários

Para uma lista completa de tipos, consulte Propriedades e tipos de valor.

Cada entidade no Cloud Datastore tem uma chave que a identifica de maneira exclusiva. A chave consiste nos seguintes componentes:

  • O namespace da entidade, que permite a multilocação
  • O tipo da entidade, que a categoriza para as consultas do Cloud Datastore
  • Um identificador da entidade individual, que pode ser:
    • uma string de nome da chave;
    • um código numérico inteiro.
  • Um caminho ancestral opcional que localiza a entidade na hierarquia do Cloud Datastore

Um aplicativo pode buscar uma entidade individual do Cloud Datastore usando a chave da entidade ou recuperar uma ou mais entidades emitindo uma consulta com base nas chaves ou nos valores de propriedade das entidades.

O SDK do App Engine para Python inclui uma biblioteca de modelagem de dados para representar entidades do Cloud Datastore como instâncias de classes do Python e para armazenar e recuperar essas entidades no Datastore.

O Cloud Datastore em si não aplica nenhuma restrição sobre a estrutura das entidades, como por exemplo, se uma determinada propriedade tem um valor de um tipo específico. Essa tarefa é do aplicativo e da biblioteca de modelagem de dados.

Tipos e identificadores

Cada entidade do Cloud Datastore é de um determinado tipo, que a categoriza para fins de consultas. Por exemplo, um aplicativo de recursos humanos pode representar cada funcionário de uma empresa com uma entidade do tipo Employee. Na API Datastore para Python, o tipo de uma entidade é determinado pela classe de modelo dela, que você define no aplicativo como uma subclasse da classe de biblioteca de modelagem de dados db.Model. O nome da classe do modelo se torna o tipo de entidades pertencentes a ela. Todos os nomes de tipo que começam com dois sublinhados (__) são reservados e não podem ser usados.

Veja no exemplo a seguir como criar uma entidade do tipo Employee, preencher os valores de propriedade e a salvar no Datastore:

import datetime
from google.appengine.ext import db

class Employee(db.Model):
  first_name = db.StringProperty()
  last_name = db.StringProperty()
  hire_date = db.DateProperty()
  attended_hr_training = db.BooleanProperty()

employee = Employee(first_name='Antonio',
                    last_name='Salieri')

employee.hire_date = datetime.datetime.now().date()
employee.attended_hr_training = True

employee.put()

A classe Employee declara quatro propriedades para o modelo de dados: first_name, last_name, hire_date e attended_hr_training. A superclasse Model garante que os atributos dos objetos Employee estejam em conformidade com esse modelo. Por exemplo, uma tentativa de atribuir um valor de string ao atributo hire_date resultaria em um erro de ambiente de execução, já que o modelo de dados de hire_date foi declarado como db.DateProperty.

Além de um tipo, cada entidade tem um identificador, que é atribuído quando ela é criada. Como ele é parte da chave da entidade, o identificador é associado permanentemente à entidade e não pode ser alterado. Ele pode ser atribuído de duas formas:

  • Seu aplicativo pode especificar sua própria string de nome de chave para a entidade.
  • O Cloud Datastore pode atribuir automaticamente um código numérico inteiro à entidade.

Para atribuir uma entidade a um nome de chave, forneça o argumento nomeado key_name ao construtor da classe de modelo ao criar a entidade:

# Create an entity with the key Employee:'asalieri'.
employee = Employee(key_name='asalieri')

Para que o Cloud Datastore atribua um código numérico automaticamente, omita o argumento key_name:

# Create an entity with a key such as Employee:8261.
employee = Employee()

Como atribuir identificadores

O Cloud Datastore pode ser configurado para gerar códigos automaticamente usando duas políticas de identificação automática diferentes:

  • A política default gera uma sequência aleatória de códigos não utilizados que são distribuídos uniformemente de forma aproximada. Cada código pode ter até 16 dígitos decimais.
  • A política legacy cria uma sequência de códigos inteiros menores não consecutivos.

Se você quiser exibir os códigos de entidade para o usuário e/ou depender da ordem deles, a melhor coisa a fazer é usar a alocação manual.

O Cloud Datastore gera uma sequência aleatória de códigos não utilizados que são distribuídos de maneira quase uniforme. Cada código pode ter até 16 dígitos decimais.

Os valores de código atribuídos pelo sistema são garantidamente exclusivos para o grupo de entidades. Se você copiar uma entidade de um grupo de entidades ou namespace para outro e quiser preservar a parte do código da chave, primeiro atribua o código para impedir que o Cloud Datastore o selecione em uma atribuição futura.

Caminhos ancestrais

As entidades do Cloud Datastore formam um espaço hierarquicamente estruturado, semelhante à estrutura de diretórios de um sistema de arquivos. Ao criar uma entidade, é possível designar outra entidade como pai e a nova é a entidade filho (observe que, diferentemente do que ocorre em um sistema de arquivos, a entidade pai não precisa existir de verdade). Uma entidade sem pai é uma entidade raiz. A associação entre uma entidade e a entidade pai é permanente e não pode ser alterada depois que a entidade é criada. O Cloud Datastore nunca atribuirá o mesmo código numérico a duas entidades com o mesmo pai ou a duas entidades raiz (sem pai).

O pai de uma entidade, o pai do pai, e assim por diante são ancestrais dela. O filho, o filho do filho, e assim por diante são descendentes dela. Uma entidade raiz e todos os descendentes pertencem ao mesmo grupo de entidades. A sequência de entidades começando com uma entidade raiz e procedendo de pai para filho, levando a uma determinada entidade, constitui o caminho ancestral dessa entidade. A chave completa que identifica a entidade consiste em uma sequência de pares de identificadores de tipo que especifica seu caminho ancestral e termina com os da própria entidade:

[Person:GreatGrandpa, Person:Grandpa, Person:Dad, Person:Me]

Para uma entidade raiz, o caminho ancestral está vazio, e a chave consiste unicamente no próprio tipo e identificador da entidade:

[Person:GreatGrandpa]

Esse conceito é ilustrado pelo seguinte diagrama:

Mostra o relacionamento da entidade raiz com entidades filho no grupo de entidades

Para criar o pai de uma entidade, use o argumento parent para o construtor da classe de modelo ao criar a entidade filho. O valor desse argumento pode ser a própria entidade pai ou a chave dela. É possível conseguir a chave chamando o método key() da entidade pai. O exemplo a seguir cria uma entidade do tipo Address e mostra duas maneiras de designar uma entidade Employee como o pai dela:

# Create Employee entity
employee = Employee()
employee.put()

# Set Employee as Address entity's parent directly...
address = Address(parent=employee)

# ...or using its key
e_key = employee.key()
address = Address(parent=e_key)

# Save Address entity to datastore
address.put()

Transações e grupos de entidades

Toda tentativa de criar, atualizar ou excluir uma entidade ocorre no contexto de uma transação. Uma única transação inclui qualquer número dessas operações. Para manter a consistência dos dados, a transação garante a aplicação de todas as suas operações no Cloud Datastore como uma unidade ou, em caso de falha de alguma operação, que nenhuma delas seja aplicada. Além disso, todas as leituras com consistência forte (consultas de ancestral ou operações de get), executadas na mesma transação, seguem um instantâneo consistente dos dados.

Como mencionado acima, um grupo de entidades é um conjunto de entidades conectadas por meio de um ancestral a um elemento raiz comum. A organização dos dados em grupos de entidades pode limitar quais transações podem ser realizadas:

  • Todos os dados acessados por uma transação devem estar contidos em, no máximo, 25 grupos de entidades.
  • Se você quiser usar consultas em uma transação, os dados precisam estar organizados em grupos de entidades para que você possa especificar filtros de ancestral que corresponderão aos dados corretos.
  • Há um limite de capacidade de gravação de aproximadamente uma transação por segundo em um único grupo de entidades. Essa limitação existe porque o Cloud Datastore executa a replicação síncrona sem mestre de cada grupo de entidades em uma ampla área geográfica para fornecer alta confiabilidade e tolerância a falhas.

Em muitos aplicativos, é aceitável usar a consistência eventual (ou seja, uma consulta que não seja de ancestral abrangendo vários grupos de entidades, que às vezes pode retornar dados um pouco desatualizados) ao ter uma visualização ampla dos dados não relacionados, e na sequência usar a consistência forte (uma consulta de ancestral ou uma operação get para uma única entidade) ao visualizar ou editar um único conjunto de dados altamente relacionados. Em tais aplicativos, geralmente é uma boa abordagem usar um grupo de entidades separado para cada conjunto de dados altamente relacionados. Para mais informações, consulte Como estruturar uma consistência forte.

Propriedades e tipos de valores

Os valores de dados associados a uma entidade consistem em uma ou mais propriedades. Cada propriedade tem um nome e um ou mais valores. Uma propriedade pode ter valores de mais de um tipo, e duas entidades podem ter valores de tipos diferentes para a mesma propriedade. As propriedades podem ser indexadas ou não (consultas que ordenam ou filtram com base em uma propriedade P ignoram entidades em que P não seja indexada). Uma entidade pode ter no máximo 20.000 propriedades indexadas.

Estes são os tipos de valor compatíveis:

Tipo de valor Tipo(s) do Python Ordem de classificação Observações
Número inteiro int
long
Numérica Número inteiro de 64 bits, assinado
Número de ponto flutuante float Numérica Precisão dupla de 64 bits,
IEEE 754
Booleano bool False<True
String de texto (curta) str
unicode
Unicode
(str tratado como ASCII)
Até 1.500 bytes
String de texto (longa) db.Text Nenhuma Até 1 megabyte

Não indexado
String de bytes (curta) db.ByteString Ordem de bytes Até 1.500 bytes
String de bytes (longa) db.Blob Nenhuma Até 1 megabyte

Não indexado
Data e hora datetime.date
datetime.time
datetime.datetime
Cronológica
Ponto geográfico db.GeoPt Por latitude
e depois por longitude
Endereço postal db.PostalAddress Unicode
Número de telefone db.PhoneNumber Unicode
Endereço de e-mail db.Email Unicode
Usuário das Contas do Google users.User Endereço de e-mail
em ordem Unicode
Identificador de mensagens instantâneas db.IM Unicode
Link db.Link Unicode
Categoria db.Category Unicode
Classificação db.Rating Numérica
Chave do Cloud Datastore db.Key Por elementos do caminho
(tipo, identificador,
tipo, identificador...)
Chave do Blobstore blobstore.BlobKey Ordem de bytes
Nulo NoneType Nenhum

Importante: é altamente recomendável não armazenar um UserProperty, porque ele inclui o endereço de e-mail e o ID exclusivo do usuário. Se um usuário alterar o endereço de e-mail dele e você comparar o User anterior armazenado com o novo valor User, eles não coincidirão.

Para strings de texto e dados binários não codificados (strings de bytes), o Cloud Datastore aceita dois tipos de valor:

  • Strings curtas (até 1500 bytes) são indexadas e podem ser usadas em condições de filtro de consulta e ordens de classificação.
  • Strings longas (até 1 megabyte) não são indexadas e não podem ser usadas em filtros de consulta e ordens de classificação.
Observação: o tipo de string de bytes longa é chamado Blob na API Cloud Datastore. Esse tipo de string não está relacionado a blobs usados na API Blobstore.

Quando uma consulta inclui uma propriedade com valores de tipos mistos, o Cloud Datastore usa uma ordem determinística baseada nas representações internas:

  1. Valores nulos
  2. Números de ponto fixo
    • Números inteiros
    • Datas e horas
    • Classificações
  3. Valores booleanos
  4. Sequências de bytes
    • String de bytes
    • String Unicode
    • Chaves do Blobstore
  5. Números de ponto flutuante
  6. Pontos geográficos
  7. Usuários das Contas do Google
  8. chaves do Cloud Datastore

Como strings de texto e de bytes longas não são indexadas, elas não têm uma ordem definida.

Como trabalhar com entidades

Os aplicativos podem usar a API Cloud Datastore para criar, recuperar, atualizar e excluir entidades. Se o aplicativo souber a chave completa de uma entidade (ou puder derivá-la da própria chave mãe, do tipo e do identificador), ele poderá usá-la para operar diretamente na entidade. Um aplicativo também pode conseguir a chave de uma entidade por meio de uma consulta do Cloud Datastore. Consulte a página Consultas do Datastore para mais informações.

Como criar uma entidade

Para criar uma nova entidade no Python, gere uma instância de uma classe de modelo, preencha as propriedades dela, se necessário, e chame o método put() para armazená-la no Datastore. Você pode especificar o nome da chave da entidade passando um argumento key_name para o construtor:

employee = Employee(key_name='asalieri',
                    first_name='Antonio',
                    last_name='Salieri')

employee.hire_date = datetime.datetime.now().date()
employee.attended_hr_training = True

employee.put()

Se o nome de chave não for fornecido, o Cloud Datastore gerará automaticamente um código numérico para a chave da entidade:

employee = Employee(first_name='Antonio',
                    last_name='Salieri')

employee.hire_date = datetime.datetime.now().date()
employee.attended_hr_training = True

employee.put()

Como recuperar uma entidade

Para recuperar uma entidade identificada por uma determinada chave, transmita o objeto Key como um argumento para a função db.get(). É possível gerar o objeto Key usando o método de classe Key.from_path(). O caminho completo é uma sequência de entidades no caminho ancestral, com cada entidade representada pelo tipo (uma sequência) dela seguido do identificador (nome da chave ou código numérico):

address_k = db.Key.from_path('Employee', 'asalieri', 'Address', 1)
address = db.get(address_k)

db.get() retorna uma instância da classe de modelo apropriada. Verifique se você importou a classe de modelo para a entidade que está sendo recuperada.

Como atualizar uma entidade

Para atualizar uma entidade atual, modifique os atributos do objeto e chame o método put() dele. Os dados do objeto substituem a entidade existente. O objeto inteiro é enviado ao Cloud Datastore a cada chamada do método put().

Para excluir uma propriedade, exclua o atributo do objeto do Python:

del address.postal_code

e salve o objeto.

Como excluir uma entidade

É possível excluir a entidade com a função db.delete() usando a chave da entidade

address_k = db.Key.from_path('Employee', 'asalieri', 'Address', 1)
db.delete(address_k)

ou chamando o método delete() da própria entidade:

employee_k = db.Key.from_path('Employee', 'asalieri')
employee = db.get(employee_k)

# ...

employee.delete()

Operações em lote

As funções db.put(), db.get() e db.delete() (e os equivalentes assíncronos delas db.put_async(), db.get_async() e db.delete_async()) podem aceitar um argumento de lista para atuar em várias entidades em uma única chamada do Cloud Datastore:

# A batch put.
db.put([e1, e2, e3])

# A batch get.
entities = db.get([k1, k2, k3])

# A batch delete.
db.delete([k1, k2, k3])

As operações em lote não alteram os custos. Você será cobrado por todas as chaves em uma operação em lote, independentemente de cada chave existir ou não. O tamanho das entidades envolvidas em uma operação não afeta o custo.

Como excluir entidades em massa

Se você precisar excluir um grande número de entidades, recomendamos usar o Cloud Dataflow para excluir entidades em massa.

Como usar uma lista vazia

Para a interface NDB, o Cloud Datastore escreveu historicamente uma lista vazia como uma propriedade omitida para propriedades estáticas e dinâmicas. Para manter a compatibilidade com versões anteriores, esse comportamento continua sendo o padrão. Para modificar isso globalmente ou por ListProperty, defina o argumento write_empty_list como true na classe Property. Após isso, a lista vazia será gravada no Cloud Datastore e poderá ser lida como uma lista vazia.

Para a interface DB, as gravações de lista vazia não eram historicamente permitidas se a propriedade fosse dinâmica. Se tentasse isso, você receberia um erro. Isso significa que não há comportamento padrão que precise ser preservado para compatibilidade com versões anteriores das propriedades dinâmicas DB. Dessa maneira, basta escrever e ler a lista vazia no modelo dinâmico sem nenhuma alteração.

No entanto, para propriedades estáticas DB, a lista vazia foi gravada como uma propriedade omitida, e esse comportamento continua por padrão para compatibilidade com versões anteriores. Se quiser ativar listas vazias para propriedades estáticas DB, defina o argumento write_empty_list como true na classe Property. Após isso, a lista vazia será gravada no Cloud Datastore.

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…

Ambiente padrão do App Engine para Python 2