Os objetos de dados no 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 Datastore é compatível com uma grande variedade de tipos de dados como 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.
Cada entidade no Datastore tem uma chave que a identifica de maneira exclusiva. A chave tem os seguintes componentes:
- O namespace da entidade, que possibilita a multilocação
- O tipo da entidade, que a categoriza para as consultas do 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 Datastore.
Um aplicativo pode buscar uma entidade individual do 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 Go inclui um pacote para representar entidades do Datastore como estruturas do Go e para armazenar e recuperar essas entidades no Datastore.
O 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.
Tipos e identificadores
Cada entidade do Datastore é de um tipo específico, que a classifica 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 Go, você especifica o tipo de entidade ao criar um datastore.Key. Por serem reservados, todos os nomes de tipo que começam com dois sublinhados (__
) não podem ser usados.
O exemplo a seguir cria uma entidade do tipo Employee
, preenche os valores da propriedade e a salva no Datastore:
O tipo Employee
declara quatro campos para o modelo de dados: FirstName
, LastName
, HireDate
e AttendedHRTraining
.
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 a própria string de nome de chave para a entidade.
- O Datastore atribui automaticamente à entidade um ID numérico inteiro.
Para atribuir um nome de chave a uma entidade, forneça um argumento stringID
não vazio para datastore.NewKey
:
Para permitir que o Datastore atribua um ID numérico automaticamente, use um argumento stringID
vazio:
Como atribuir identificadores
O 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 IDs não utilizados que são aproximadamente distribuídos de maneira uniforme. Cada ID pode ter até 16 dígitos decimais. - A política
legacy
cria uma sequência de IDs inteiros menores e não consecutivos.
Para exibir os IDs de entidade para o usuário e/ou depender da ordem deles, use a alocação manual.
O Datastore gera uma sequência aleatória de IDs não utilizados que são distribuídos de maneira quase uniforme. Cada ID pode ter até 16 dígitos decimais.
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 mãe e a nova como filha. Ao contrário do que ocorre em um sistema de arquivos, a entidade mãe não precisa existir de verdade. Uma entidade sem mãe é uma entidade raiz. A associação entre uma entidade e a mãe é permanente e não pode ser alterada depois que a entidade é criada. O Cloud Datastore nunca atribuirá o mesmo ID numérico a duas entidades com a mesma mãe ou a duas entidades raiz (sem mãe).
A mãe de uma entidade, a mãe da mãe, e assim por diante são ancestrais dela. A filha, a filha da filha, 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 prosseguindo de pai para filho, levando a uma determinada entidade, constitui o caminho do ancestral dessa entidade. A chave completa que identifica a entidade consiste em uma sequência de pares de identificadores de tipo que especifica o 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:
Para designar o pai de uma entidade, use o argumento parent
para datastore.NewKey
. O valor desse argumento precisa ser a chave da entidade pai. O exemplo a seguir cria uma entidade do tipo Address
e designa uma entidade Employee
como pai:
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 pode incluir qualquer número dessas operações. Para manter a consistência dos dados, a transação assegura que todas as operações que ela contém sejam aplicadas ao Datastore como uma unidade ou, se alguma das operações falhar, que nenhuma delas seja aplicada. Além disso, todas as leituras com consistência forte (consultas ou operações get de ancestral) 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, para fornecer alta confiabilidade e tolerância a falhas, o Datastore executa a replicação síncrona sem mestre de cada grupo de entidades em uma ampla área geográfica.
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) para uma visualização ampla de dados não relacionados e depois usar a consistência forte (uma consulta de ancestral ou uma operação get
para uma única entidade) para 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 Go | Ordem de classificação | Observações |
---|---|---|---|
Número inteiro | int int8 int16 int32 int64 |
Numérico | Número inteiro de 64 bits, assinado |
Número de ponto flutuante | float32 float64 |
Numérico | Precisão dupla de 64 bits, IEEE 754 |
Booleano | bool |
false <true |
|
String (curta) | string |
Unicode |
Até 1500 bytes. Os valores superiores a 1500 bytes resultam em um erro no tempo de execução. |
String (longa) | string (com noindex ) |
Nenhum | Até 1 megabyte Não indexado |
Fatia de bytes (curta) | datastore.ByteString |
Ordem de bytes | Até 1500 bytes. Os valores superiores a 1500 bytes resultam em um erro no tempo de execução. |
Fatia de bytes (longa) | []byte |
Nenhum | Até 1 megabyte Não indexado |
Data e hora | time.Time |
Cronológica | |
Ponto geográfico | appengine.GeoPoint |
Por latitude, e depois longitude |
|
Chave do Datastore | *datastore.Key |
Por elementos do caminho (tipo, identificador, tipo, identificador...) |
|
Chave Blobstore | appengine.BlobKey |
Ordem de bytes |
Você também pode usar um struct
ou slice
para agregar propriedades. Consulte a referência do Datastore para mais detalhes.
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
- fatias de bytes (curtas)
- string Unicode
- Chaves do Blobstore
- Números de ponto flutuante
- pontos geográficos
- Chaves do armazenamento de dados
Como as fatias de bytes e as strings longas não são indexadas, elas não têm ordem definida.
Trabalhar com entidades
Os aplicativos podem usar a API 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 pai, tipo e identificador, ele pode usá-la para operar diretamente na entidade. O aplicativo também pode conseguir a chave de uma entidade por meio de uma consulta do Datastore. Para mais informações, consulte a página Consultas do Datastore.
Como criar uma entidade
Para criar uma nova entidade no Go, gere uma instância de estrutura do Go preenchendo os campos dela e chamando datastore.Put
para salvá-la no Datastore. Apenas os campos exportados (que começam com uma letra maiúscula) serão salvos no Datastore. É possível especificar o nome de chave da entidade transmitindo um argumento stringID
não vazio para datastore.NewKey
:
Se você fornecer um nome de chave vazio ou usar datastore.NewIncompleteKey
, o Datastore gerará automaticamente um ID numérico para a chave da entidade:
Recuperar uma entidade
Para recuperar uma entidade identificada por uma determinada chave, transmita o *datastore.Key
como um argumento para a função datastore.Get
. É possível gerar o *datastore.Key
usando a função datastore.NewKey
.
O datastore.Get
preenche uma instância da estrutura do Go apropriada.
Como atualizar uma entidade
Para atualizar uma entidade atual, modifique os atributos da estrutura e, em seguida, chame datastore.Put
. Os dados substituem a entidade existente. O objeto inteiro é enviado ao Datastore com todas as chamadas para datastore.Put
.
Como excluir uma entidade
Dada a chave de uma entidade, é possível excluir a entidade com a função datastore.Delete
:
Operações em lote
datastore.Put
,
datastore.Get
e
datastore.Delete
têm variantes em massa chamadas
datastore.PutMulti
,
datastore.GetMulti
e
datastore.DeleteMulti
.
Eles permitem atuar em várias entidades em uma única chamada do Datastore:
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.