O Firestore no modo Datastore (Datastore) é compatível com vários tipos de dados para valores de propriedade. Estes são alguns deles:
- 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.
Propriedades e tipos de valor
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:
Quando uma consulta envolve um campo com valores de tipos mistos, o Firestore usa uma ordem determinista com base nas representações internas:
- Valores nulos
- Números de ponto fixo
- Números inteiros
- datas e horas
- Valores booleanos
- Sequências de bytes
- String Unicode
- Chaves do Blobstore
- Números de ponto flutuante
- Chaves do armazenamento de dados
Como strings de texto e de bytes longas não são indexadas, elas não têm uma ordem definida.
Tipos de propriedade
O NDB aceita os seguintes tipos de propriedade:
Tipo de propriedade | Descrição |
---|---|
IntegerProperty | Inteiro assinado de 64 bits |
FloatProperty | Número de ponto flutuante de precisão dupla |
BooleanProperty | Booleano |
StringProperty | String Unicode, até 1.500 bytes indexados |
TextProperty | String Unicode, comprimento ilimitado, não indexado |
BlobProperty | String de bytes não interpretada: se você definir indexed=True , até 1.500 bytes, indexado; se indexed for False (o padrão), comprimento ilimitado, não indexado.Argumento de palavra-chave opcional: compressed .
|
DateTimeProperty
| Data e hora (consulte Propriedades de data e hora) |
DateProperty
| Data (consulte Propriedades de data e hora) |
TimeProperty
| Hora (consulte Propriedades de data e hora) |
GeoPtProperty
| Local geográfico. Este é um objeto ndb.GeoPt .
O objeto tem atributos lat e lon , ambos flutuantes.
Crie um com dois flutuantes como ndb.GeoPt(52.37, 4.88) ou com uma string ndb.GeoPt("52.37, 4.88") .
Na verdade, essa é a mesma classe de
db.GeoPt .
|
KeyProperty | Chave do Datastore Argumento de palavra-chave opcional: kind=kind, para exigir que chaves atribuídas a essa propriedade sempre tenham o tipo indicado. Pode ser uma string ou uma subclasse Model. |
BlobKeyProperty
| Chave do Blobstore Corresponde a BlobReferenceProperty na API db anterior, mas o valor da propriedade é BlobKey em vez de uma BlobInfo , é possível criar um BlobInfo com base nele usando BlobInfo(blobkey)
|
UserProperty | Objeto do usuário |
StructuredProperty
| Inclui um tipo de modelo dentro de outro, por valor (consulte Propriedades estruturadas) |
LocalStructuredProperty
| Semelhante a StructuredProperty , mas a representação no disco é um blob opaco e não é indexada, consulte Propriedades estruturadas.Argumento de palavra-chave opcional: compressed .
|
JsonProperty
| Value é um objeto do Python (como uma lista ou um dict ou uma string) serializável usando-se o módulo json do Python. O Datastore armazena a serialização JSON como um blob. Não indexado por padrão.Argumento de palavra-chave opcional: compressed .
|
PickleProperty
| Value é um objeto do Python (como uma lista ou um dict ou uma string) serializável usando-se o protocolo de seleção do Python serializável. O Datastore armazena a serialização de seleção como um blob. Não indexado por padrão. Argumento de palavra-chave opcional: compressed .
|
GenericProperty | Valor genérico mais usada pela classe Expando , mas também utilizável de maneira explícita. O tipo pode ser qualquer int , long , float , bool , str , unicode , datetime , Key , BlobKey , GeoPt , User , None .
|
ComputedProperty
| Valor computado com base em outras propriedades por uma função definida pelo usuário. Consulte Propriedades computadas. |
Algumas propriedades têm um argumento de palavra-chave opcional, compressed
. Caso a propriedade tenha compressed=True
, os dados dela são compactados com gzip em disco.
Ele ocupa menos espaço, mas precisa de CPU para codificar/decodificar em operações de gravação e leitura.
A compactação e a descompactação são "vagarosas". Um valor de propriedade compactado só será descompactado na primeira vez em que você acessá-lo. Se você ler uma entidade que contiver um valor de propriedade compactado e reescrevê-lo sem acessar a propriedade compactada, ela não será descompactada e compactada. O cache no contexto também participa desse esquema vagaroso, mas o memcache sempre armazena o valor compactado para propriedades compactadas.
Por causa do tempo de CPU extra necessário para compactação, normalmente seria melhor usar apenas propriedades compactadas se os dados fossem grandes demais para caber nelas. Lembre-se de que a compactação baseada em gzip não costuma ser eficiente para imagens e outros dados de mídia, porque esses formatos já estão compactados usando-se um algoritmo de compactação específico de mídia (por exemplo, JPEG para imagens).
Opções de propriedade
A maioria dos tipos de propriedade aceita alguns argumentos padrão. O primeiro é um argumento posicional opcional que especifica o nome do Datastore da propriedade. Você pode usá-lo para dar à propriedade um nome diferente no Datastore do que o aquele usado do ponto de vista do aplicativo. Um uso comum para isso é reduzir o espaço no Datastore, permitindo que ele use nomes de propriedade abreviados enquanto o código usa nomes mais longos e significativos. Por exemplo,
Isso é especialmente útil para propriedades repetidas para as quais você espera muitos valores por entidade.
Além disso, a maioria dos tipos de propriedade aceita os seguintes argumentos de palavra-chave:
Argumento | Tipo | Padrão | Descrição |
---|---|---|---|
indexed | bool | Normalmente True | Inclua a propriedade nos índices do Datastore. Caso False , os valores não podem ser consultados, mas as gravações são mais rápidas. Nem todos os tipos de propriedade aceitam indexação. A configuração de indexed como True falha para eles.As propriedades não indexadas custam menos operações de gravação do que as propriedades indexadas. |
repeated | bool | False | O valor da propriedade é uma lista do Python que contém valores do tipo subjacente (consulte Propriedades repetidas). Não pode ser combinado com required=True ou default=True .
|
required | bool | False | A propriedade precisa ter um valor especificado. |
default | Tipo subjacente da propriedade | None | Valor padrão da propriedade, caso nenhum tenha sido especificado explicitamente. |
choices | Lista de valores de tipo subjacente | None | Lista opcional de valores permitidos. |
validator | Função | None | Função opcional para validar e possivelmente forçar o valor. Será chamada com argumentos (prop, value) e precisará retornar o valor (possivelmente forçado) ou gerar uma exceção. Chamar a função novamente em um valor forçado não precisa modificar o valor ainda mais.
Por exemplo, retornar |
verbose_name | string | None
| Rótulo HTML opcional a ser usado em bibliotecas de formulário da Web como jinja2. |
Propriedades repetidas
Qualquer propriedade com repeated=True
torna-se uma propriedade repetida.
A propriedade utiliza uma lista de valores do tipo subjacente, em vez de um único valor.
Por exemplo, o valor de uma propriedade definida com IntegerProperty(repeated=True)
é uma lista de números inteiros.
O Datastore pode ver vários valores para essa propriedade. Um registro de índice separado é criado para cada valor. Isso afeta a semântica de consulta. Consulte Como consultar propriedades repetidas para ver um exemplo.
Este exemplo usa uma propriedade repetida:
...
Isso cria uma entidade do Datastore com o seguinte conteúdo:
Ao consultar a propriedade tags
, essa entidade atenderá a uma consulta para 'python'
ou 'ruby'
.
Ao atualizar uma propriedade repetida, você poderá atribuir a ela uma nova lista ou alterar a lista existente.
Quando você atribui uma nova lista, os tipos dos itens de lista são validados imediatamente. Os tipos de item inválidos (por exemplo, atribuição de [1, 2]
a art.tags
acima) geram uma exceção.
Quando você altera a lista, a mudança não é validada imediatamente.
Em vez disso, o valor será validado quando você gravar a entidade no Datastore.
O Datastore preserva a ordem dos itens da lista em uma propriedade repetida. Dessa maneira, você atribui um significado à ordem.
Propriedades de data e hora
Três tipos de propriedade estão disponíveis para armazenar valores relacionados a data e hora:
DateProperty
TimeProperty
DateTimeProperty
Eles utilizam valores pertencentes às classes correspondentes (date
, time
, datetime
) do módulo datetime
do Python padrão.
O mais geral dos três é DateTimeProperty
, que denota uma data do calendário e uma hora do dia. Às vezes, outros são úteis para fins especiais que exigem apenas uma data (como uma data de nascimento) ou apenas uma hora (como um horário de reunião).
Por motivos técnicos, DateProperty
e TimeProperty
são subclasses de DateTimeProperty
, mas você não precisa depender desse relacionamento de herança (e observe que ele difere dos relacionamentos de herança entre as classes subjacentes definidas pelo próprio módulo datetime
).
Observação: as horas do App Engine são sempre expressas na Hora universal coordenada (UTC, na sigla em inglês). Isso ganha relevância caso você use a data ou a hora atual (datetime.datetime.now()
) como um valor ou converta entre objetos de data e hora e carimbos de data/hora POSIX ou tuplas de hora.
No entanto, nenhuma informação de fuso horário explícito é armazenada no Datastore. Dessa maneira, caso tenha cuidado, você pode usá-la para representar horas locais em qualquer fuso horário, caso você use a hora atual ou as conversões.
Cada uma dessas propriedades tem duas opções de palavra-chave booleanas extras:
Opção | Descrição |
---|---|
auto_now_add
| Defina a propriedade como data/hora atual quando a entidade é criada. Substitua manualmente essa propriedade. Quando a entidade é atualizada, a propriedade não é alterada. Para esse comportamento, use auto_now .
|
auto_now
| Defina a propriedade como data/hora atual quando a entidade é criada e sempre que ela é atualizada. |
Essas opções não podem ser combinadas com repeated=True
.
As duas assumem como padrão False
. Se ambas estiverem configuradas como True
, auto_now
terá precedência.
É possível modificar o valor de uma propriedade com auto_now_add=True
, mas não para um com auto_now=True
.
O valor automático não será gerado até a entidade ser gravada, ou seja, essas opções não fornecem padrões dinâmicos.
Esses detalhes são diferentes da db API anterior.
Observação: quando uma transação que grava uma propriedade com auto_now_add=True
falhar e for repetida posteriormente, ela reutilizará o mesmo valor de hora da original, em vez de atualizá-la para a hora da nova tentativa. Se a transação falhar permanentemente, o valor da propriedade ainda será definido na cópia da entidade na memória.
Propriedades estruturadas
Estruture as propriedades de um modelo.
Por exemplo, defina uma classe de modelo Contact que contém uma lista de endereços, cada um com estrutura interna.
Propriedades estruturadas, aquelas do tipo StructuredProperty
, permitem fazer isso. Por exemplo:
...
...
Isso cria uma única entidade do Datastore com as seguintes propriedades:
A leitura de uma entidade desse tipo recria a entidade original Contact
exatamente.
As instâncias de Address
são definidas usando-se a mesma sintaxe das classes de modelo, mas elas não são entidades completas.
Elas não têm as próprias chaves no Datastore.
Elas não podem ser recuperadas independentemente da entidade Contact
à qual pertencem.
Porém, um aplicativo pode consultar os valores dos campos individuais. Consulte Como filtrar valores de propriedade estruturada.
Observe que address.type
, address.street
e address.city
são exibidos como matrizes paralelas do ponto de vista do Datastore, mas a biblioteca NDB oculta esse aspecto e cria a lista correspondente de instâncias Address
.
É possível especificar as opções de propriedade comuns para propriedades estruturadas (exceto indexed
). O nome do Datastore é o segundo argumento posicional nesse caso. O primeiro é a classe de modelo usada para definir a subestrutura.
Quando não precisar consultar as propriedades internas de uma subestrutura, você poderá usar uma propriedade estruturada local (LocalStructuredProperty
). Se você substituir StructuredProperty
por LocalStructuredProperty
no exemplo acima, o comportamento do código do Python será o mesmo, mas o Datastore verá apenas um blob opaco para cada endereço. A entidade guido
criada no exemplo seria armazenada assim:
name = 'Guido'
address = <opaque blob for {'type': 'home', 'city': 'Amsterdam'}>
address = <opaque blob for {'type': 'work', 'city': 'SF',
'street': 'Spear St'}>
A entidade será lida corretamente. Como propriedades desse tipo nunca são indexadas, não é possível consultar valores de endereço.
Observação: uma StructuredProperty
com uma propriedade aninhada (independentemente de ser estruturada ou não) só aceita uma única camada de propriedades repetidas. A StructuredProperty
pode ser repetida, ou a propriedade aninhada pode ser repetida, mas não ambas. Uma solução alternativa é usar LocalStructuredProperty
, que não tem essa restrição (mas não permite consultas em valores da propriedade).
Propriedades computadas
Propriedades computadas (ComputedProperty
) são propriedades somente leitura com um valor computado com base em outros valores de propriedade por uma função fornecida pelo aplicativo. Uma propriedade computada só aceita os tipos compatíveis por propriedades genéricas. O valor computado é gravado no Datastore. Dessa maneira, ele pode ser consultado e exibido no visualizador do Datastore, mas o valor armazenado é ignorado quando a entidade é lida do Datastore. Em vez disso, o valor é recomputado chamando-se a função sempre que o valor é solicitado. Exemplo:
...
Isso armazena uma entidade com os seguintes valores de propriedade:
Se mudarmos o nome para "Nickie" e pedirmos o valor de name_lower
, ele retornará "nickie":
Observação: use ComputedProperty
caso o aplicativo consulte o valor computado. Caso você queira apenas usar a versão derivada no código do Python, defina um método regular ou use a @property
interna do Python.
Observação: se você criar um modelo sem uma chave especificada manualmente e, em vez disso, depender do Datastore para gerar automaticamente o ID da entidade, o primeiro put()
em um ComputedProperty
não poderá ler o campo do ID porque esse campo é computado antes da geração do ID.
Se você precisar de um ComputedProperty
que use o ID da entidade, use o método allocate_ids
para gerar um ID e uma chave para criar a entidade. Assim, o ComputedProperty
criará uma referência ao ID no primeiro put() da entidade.
Propriedades da mensagem RPC do protocolo do Google
A biblioteca de RPC do Protocolo do Google usa objetos
Message
em dados estruturados. Esses objetos podem representar solicitações, respostas ou outros elementos do RPC. O NDB fornece uma API para armazenar objetos Message
RPC do protocolo do Google como propriedades da entidade.
Suponha que você defina uma subclasse Message
:
...
Armazene objetos Note
no Datastore como valores de propriedade da entidade usando a API msgprop
do NDB.
...
...
Se você quiser consultar nomes de campo, eles precisarão ser indexados.
É possível especificar uma lista de nomes de campos que serão indexados com o parâmetro indexed_fields
para MessageProperty
.
MessageProperty
aceita muitas, mas não todas as opções de propriedade. Ela aceita estas opções:
name
repeated
required
default
choices
validator
verbose_name
As propriedades de mensagem não aceitam a opção da propriedade indexed
. Não é possível indexar valores Message
. Você pode indexar campos de uma mensagem conforme descrito acima.
As mensagens aninhadas (usando MessageField
) também funcionam:
...
MessageProperty
tem uma opção de propriedade especial, protocol
, que especifica como o objeto de mensagem é serializado para o Datastore. Os valores são nomes de protocolo usados pela classe protorpc.remote.Protocols
. Os nomes de protocolo compatíveis são protobuf
e protojson
. O padrão é protobuf
.
msgprop
também define EnumProperty
, um tipo de propriedade que pode ser usado para armazenar um valor protorpc.messages.Enum
em uma entidade. Exemplo:
...
...
EnumProperty
armazena o valor como um inteiro. Na verdade, EnumProperty
é uma subclasse de IntegerProperty
.
Isso significa que você pode renomear os valores de enum sem precisar modificar entidades já armazenadas, mas não pode renumerá-los.
A EnumProperty aceita as seguintes opções de propriedade:
name
indexed
repeated
required
default
choices
validator
verbose_name
Sobre modelos de entidade NDB
Um modelo de entidade NDB pode definir propriedades. As propriedades de entidade são parecidas com membros de dados de classes do Python, uma maneira estruturada de armazenar dados. Elas também são parecidas com campos em um esquema de banco de dados.
Um aplicativo típico define um modelo de dados especificando uma classe herdada de Model
com alguns atributos da classe de propriedade.
Por exemplo,
...
Aqui, username
, userid
e email
são propriedades de Account
.
Há diversos outros tipos de propriedade. Alguns são úteis para representar datas e horas e têm recursos de atualização automática práticos.
Um aplicativo pode ajustar o comportamento de uma propriedade especificando opções na propriedade. Elas podem facilitar a validação, definir os padrões ou alterar a indexação de consultas.
Um modelo pode ter propriedades mais complexas. As propriedades repetidas são semelhantes a uma lista. As propriedades estruturadas são semelhantes a um objeto. As propriedades computadas somente leitura são definidas por meio de funções. Isso facilita definir uma propriedade em termos de uma ou mais outras propriedades. Os modelos Expando podem definir propriedades de maneira dinâmica.