Los objetos de datos de Datastore se denominan entidades. Una entidad tiene una o varias propiedades con nombre, cada una de las cuales puede tener uno o varios valores. Las entidades del mismo tipo no tienen por qué tener las mismas propiedades, y los valores de una entidad para una propiedad determinada no tienen por qué ser todos del mismo tipo de datos. Si es necesario, una aplicación puede establecer y aplicar estas restricciones en su propio modelo de datos.
Datastore admite distintos tipos de datos para los valores de las propiedades. Entre ellos, se incluyen los siguientes:
- Números enteros
- Números de punto flotante
- Cadenas
- Fechas
- Datos binarios
Para ver una lista completa de los tipos, consulta Propiedades y tipos de valor.
Cada entidad de Datastore tiene una clave que la identifica de forma única. La clave consta de los siguientes componentes:
- El espacio de nombres de la entidad, que permite la arquitectura multicliente
- El tipo de la entidad, que la clasifica para las consultas de Datastore
- Un identificador de la entidad individual, que puede ser uno de los siguientes:
- Una cadena key name
- un ID numérico entero
- Una ruta de ancestro opcional que indica la ubicación de la entidad en la jerarquía de Datastore
Una aplicación puede obtener una entidad individual de Datastore mediante la clave de la entidad o puede recuperar una o varias entidades enviando una consulta basada en las claves o los valores de propiedad de las entidades.
El SDK de Java App Engine incluye una API sencilla, proporcionada en el paquete com.google.appengine.api.datastore
, que admite las funciones de Datastore directamente. Todos los ejemplos de este documento se basan en esta API de bajo nivel. Puedes usarla directamente en tu aplicación o como base para crear tu propia capa de gestión de datos.
Datastore no aplica ninguna restricción a la estructura de las entidades, como si una propiedad determinada tiene un valor de un tipo concreto. Esta tarea se deja a la aplicación.
Tipos e identificadores
Cada entidad de Datastore es de un tipo concreto,que clasifica la entidad para las consultas. Por ejemplo, una aplicación de recursos humanos puede representar a cada empleado de una empresa con una entidad de tipo Employee
. En la API Java Datastore, se especifica el tipo de una entidad al crearla, como argumento del constructor Entity()
. Todos los nombres de tipos que empiezan por dos guiones bajos (__
) están reservados y no se pueden usar.
En el siguiente ejemplo se crea una entidad de tipo Employee
, se rellenan los valores de sus propiedades y se guarda en Datastore:
Además de un tipo, cada entidad tiene un identificador, que se asigna cuando se crea la entidad. Como forma parte de la clave de la entidad, el identificador se asocia de forma permanente a la entidad y no se puede cambiar. Se puede asignar de dos formas:
- Tu aplicación puede especificar su propia cadena nombre de clave para la entidad.
- Puedes hacer que Datastore asigne automáticamente a la entidad un ID numérico entero.
Para asignar un nombre de clave a una entidad, proporciona el nombre como segundo argumento al constructor cuando crees la entidad:
Para que Datastore asigne un ID numérico automáticamente, omite este argumento:
Asignar identificadores
Datastore se puede configurar para generar IDs automáticos mediante dos políticas de IDs automáticos diferentes:
- La política
default
genera una secuencia aleatoria de IDs no utilizados que se distribuyen de forma aproximadamente uniforme. Cada ID puede tener hasta 16 dígitos decimales. - La política
legacy
crea una secuencia de IDs de números enteros más pequeños no consecutivos.
Si quieres mostrar los IDs de entidad al usuario o depender de su orden, lo mejor es usar la asignación manual.
Datastore genera una secuencia aleatoria de IDs no utilizados que se distribuyen de forma aproximadamente uniforme. Cada ID puede tener hasta 16 dígitos decimales.
Rutas de ancestros
Las entidades de Cloud Datastore forman un espacio estructurado jerárquicamente similar a la estructura de directorios de un sistema de archivos. Cuando creas una entidad, puedes designar otra entidad como principal. La nueva entidad será una secundaria de la entidad principal (ten en cuenta que, a diferencia de lo que ocurre en un sistema de archivos, la entidad principal no tiene por qué existir). Una entidad sin elemento superior es una entidad raíz. La asociación entre una entidad y su elemento superior es permanente y no se puede cambiar una vez que se ha creado la entidad. Cloud Datastore nunca asignará el mismo ID numérico a dos entidades con el mismo elemento superior ni a dos entidades raíz (aquellas que no tienen un elemento superior).
El elemento superior de una entidad, el elemento superior del elemento superior, etc., son sus ancestros. Sus elementos secundarios, los elementos secundarios de los elementos secundarios, etc., son sus descendientes. Una entidad raíz y todos sus descendientes pertenecen al mismo grupo de entidades. La secuencia de entidades que empieza con una entidad raíz y continúa de la entidad superior a la secundaria hasta llegar a una entidad determinada constituye la ruta de ancestros de esa entidad. La clave completa que identifica la entidad consta de una secuencia de pares tipo-identificador que especifican su ruta de ancestros y termina con los de la propia entidad:
[Person:GreatGrandpa, Person:Grandpa, Person:Dad, Person:Me]
En el caso de una entidad raíz, la ruta de ancestro está vacía y la clave se compone únicamente del tipo y el identificador de la entidad:
[Person:GreatGrandpa]
Este concepto se ilustra en el siguiente diagrama:
Para designar el elemento superior de una entidad, proporciona la clave de la entidad superior como argumento
del constructor
Entity()
al crear la entidad secundaria. Para obtener la clave, llama al método getKey()
de la entidad principal:
Si la nueva entidad también tiene un nombre de clave, proporciona el nombre de la clave como segundo argumento al constructor Entity()
y la clave de la entidad principal como tercer argumento:
Transacciones y grupos de entidades
Cada intento de crear, actualizar o eliminar una entidad se lleva a cabo en el contexto de una transacción. Una sola transacción puede incluir cualquier número de estas operaciones. Para mantener la coherencia de los datos, la transacción asegura que todas las operaciones que contiene se apliquen a Datastore como una unidad o, si falla alguna de las operaciones, que no se aplique ninguna. Además, todas las lecturas con coherencia fuerte (consultas de ancestros o gets) que se realicen en la misma transacción observan una instantánea coherente de los datos.
Como hemos mencionado anteriormente, un grupo de entidades es un conjunto de entidades conectadas por ascendencia a un elemento raíz común. La organización de los datos en grupos de entidades puede limitar las transacciones que se pueden realizar:
- Todos los datos a los que accede una transacción deben estar incluidos en un máximo de 25 grupos de entidades.
- Si quiere usar consultas en una transacción, sus datos deben organizarse en grupos de entidades de forma que pueda especificar filtros de ancestros que coincidan con los datos correctos.
- Hay un límite de rendimiento de escritura de aproximadamente una transacción por segundo en un solo grupo de entidades. Esta limitación se debe a que Datastore realiza una replicación síncrona sin maestro de cada grupo de entidades en una zona geográfica amplia para ofrecer una alta fiabilidad y tolerancia a fallos.
En muchas aplicaciones, se puede usar la coherencia final (es decir, una consulta que no sea de ancestro y que abarque varios grupos de entidades, que a veces puede devolver datos ligeramente obsoletos) para obtener una visión general de datos no relacionados y, a continuación, usar la coherencia fuerte (una consulta de ancestro o un get
de una sola entidad) para ver o editar un solo conjunto de datos muy relacionados. En estas aplicaciones, suele ser una buena estrategia usar un grupo de entidades independiente para cada conjunto de datos muy relacionados.
Para obtener más información, consulta Estructurar datos para conseguir una coherencia inmediata.
Propiedades y tipos de valores
Los valores de datos asociados a una entidad constan de una o varias propiedades. Cada propiedad tiene un nombre y uno o varios valores. Una propiedad puede tener valores de más de un tipo, y dos entidades pueden tener valores de tipos diferentes para la misma propiedad. Las propiedades pueden estar indexadas o no (las consultas que ordenan o filtran por una propiedad P ignorarán las entidades en las que P no esté indexada). Una entidad puede tener como máximo 20.000 propiedades indexadas.
Se admiten los siguientes tipos de valores:
Tipo de valor | Tipo(s) de Java | Ordenar por | Notas |
---|---|---|---|
Entero | short int long java.lang.Short java.lang.Integer java.lang.Long |
Numérico | Se almacena como un entero largo y, a continuación, se convierte al tipo de campo. Los valores fuera del intervalo provocan un desbordamiento. |
Número de punto flotante | float double java.lang.Float java.lang.Double |
Numérico | Doble precisión de 64 bits, IEEE 754 |
Booleano | boolean java.lang.Boolean |
false <true |
|
Cadena de texto (corta) | java.lang.String |
Unicode | Hasta 1500 bytes Si el valor supera los 1500 bytes, se produce un error IllegalArgumentException |
Cadena de texto (larga) | com.google.appengine.api.datastore.Text |
Ninguno | Hasta 1 megabyte Sin indexar |
cadena de bytes (corta) | com.google.appengine.api.datastore.ShortBlob |
Orden de bytes | Hasta 1500 bytes Si los valores superan los 1500 bytes, se produce un error IllegalArgumentException |
Cadena de bytes (larga) | com.google.appengine.api.datastore.Blob |
Ninguno | Hasta 1 megabyte Sin indexar |
Fecha y hora | java.util.Date |
Cronológico | |
Punto geográfico | com.google.appengine.api.datastore.GeoPt |
Por latitud, y luego por longitud |
|
Dirección postal | com.google.appengine.api.datastore.PostalAddress |
Unicode | |
Número de teléfono | com.google.appengine.api.datastore.PhoneNumber |
Unicode | |
Dirección de correo electrónico | com.google.appengine.api.datastore.Email |
Unicode | |
usuarios de Cuentas de Google | com.google.appengine.api.users.User |
Dirección de correo electrónico en orden Unicode |
|
Identificador de mensajería instantánea | com.google.appengine.api.datastore.IMHandle |
Unicode | |
Enlace | com.google.appengine.api.datastore.Link |
Unicode | |
Categoría | com.google.appengine.api.datastore.Category |
Unicode | |
Valoración | com.google.appengine.api.datastore.Rating |
Numérico | |
Clave de Datastore | com.google.appengine.api.datastore.Key o el objeto al que se hace referencia (como elemento secundario) |
Por elementos de ruta (tipo, identificador, tipo, identificador...) |
Hasta 1500 bytes Si los valores superan los 1500 bytes, se produce un error IllegalArgumentException |
Clave de Blobstore | com.google.appengine.api.blobstore.BlobKey |
Orden de bytes | |
Entidad insertada | com.google.appengine.api.datastore.EmbeddedEntity |
Ninguno | No indexado |
Nulo | null |
Ninguno |
Importante: Le recomendamos que no almacene un users.User
como valor de propiedad, ya que incluye la dirección de correo electrónico junto con el ID único. Si un usuario cambia su dirección de correo y comparas el valor antiguo almacenado user.User
con el nuevo user.User
, no coincidirán. En su lugar, use el User
valor del ID de usuario como identificador único estable del usuario.
En el caso de las cadenas de texto y los datos binarios sin codificar (cadenas de bytes), Datastore admite dos tipos de valores:
- Las cadenas cortas (de hasta 1500 bytes) se indexan y se pueden usar en condiciones de filtro de consultas y en criterios de ordenación.
- Las cadenas largas (de hasta 1 megabyte) no se indexan y no se pueden usar en filtros de consultas ni en criterios de ordenación.
Blob
en la API de Datastore. Este tipo no está relacionado con los blobs que se usan en la API Blobstore.
Cuando una consulta incluye una propiedad con valores de tipos mixtos, Datastore usa un orden determinista basado en las representaciones internas:
- valores nulos
- Números de coma fija
- Números enteros
- Fechas y horas
- Valoraciones
- valores booleanos
- Secuencias de bytes
- Cadena de bytes
- Cadena Unicode
- claves del almacén de blob
- Números de punto flotante
- Puntos geográficos
- Usuarios de cuentas de Google
- Claves de Datastore
Como no se indexan las cadenas de texto largas, las cadenas de bytes largas ni las entidades insertadas, no tienen ningún orden definido.
.Trabajar con entidades
Las aplicaciones pueden usar la API Datastore para crear, recuperar, actualizar y eliminar entidades. Si la aplicación conoce la clave completa de una entidad (o puede obtenerla a partir de su clave principal, su tipo y su identificador), puede usarla para operar directamente en la entidad. Una aplicación también puede obtener la clave de una entidad como resultado de una consulta de Datastore. Consulta la página Consultas de Datastore para obtener más información.
La API de Java Datastore usa métodos de la interfaz DatastoreService
para operar en entidades. Para obtener un objeto DatastoreService
, llama al método estático DatastoreServiceFactory.getDatastoreService()
:
Crear una entidad
Para crear una entidad, debes crear una instancia de la clase Entity
y proporcionar el tipo de entidad como argumento al constructor Entity()
.
Después de rellenar las propiedades de la entidad, si es necesario, guárdala en el almacén de datos pasándola como argumento al método DatastoreService.put()
. Puedes especificar el nombre de la clave de la entidad enviándolo como segundo argumento al constructor:
Si no proporcionas un nombre de clave, Datastore generará automáticamente un ID numérico para la clave de la entidad:
Recuperar una entidad
Para obtener una entidad identificada por una clave determinada, pasa el objeto Key
al método DatastoreService.get()
:
Actualizar una entidad
Para actualizar una entidad, modifica los atributos del objeto Entity y, a continuación, pásalo al método DatastoreService.put()
. Los datos del objeto sobrescriben la entidad existente. El objeto completo se envía a Datastore con cada llamada a put()
.
Eliminar una entidad
Si tienes la clave de una entidad, puedes eliminarla con el método DatastoreService.delete()
:
Propiedades repetidas
Puedes almacenar varios valores en una sola propiedad.
Entidades insertadas
A veces, puede que te resulte útil insertar una entidad como propiedad de otra. Esto puede ser útil, por ejemplo, para crear una estructura jerárquica de valores de propiedad en una entidad. La clase de Java EmbeddedEntity
te permite hacer lo siguiente:
Cuando se incluye una entidad insertada en los índices, puedes hacer consultas sobre las subpropiedades. Si excluyes una entidad insertada de la indexación, también se excluirán todas las subpropiedades. Opcionalmente, puedes asociar una clave a una entidad insertada, pero (a diferencia de una entidad completa) la clave no es obligatoria y, aunque esté presente, no se puede usar para recuperar la entidad.
En lugar de rellenar las propiedades de la entidad insertada manualmente, puedes usar el método setPropertiesFrom()
para copiarlas de una entidad que ya tengas:
Más adelante, puedes usar el mismo método para recuperar la entidad original a partir de la entidad insertada:
Operaciones por lotes
Los métodos DatastoreService
put()
, get()
y delete()
(y sus equivalentes de AsyncDatastoreService) tienen versiones por lotes que aceptan un objeto iterable (de la clase Entity
para put()
, Key
para get()
y delete()
) y lo usan para operar en varias entidades en una sola llamada a Datastore:
Estas operaciones por lotes agrupan todas las entidades o claves por grupo de entidades y, a continuación, realizan la operación solicitada en cada grupo de entidades en paralelo. Estas llamadas por lotes son más rápidas que las llamadas independientes para cada entidad, ya que solo incurren en la sobrecarga de una llamada de servicio. Si hay varios grupos de entidades implicados, el trabajo de todos los grupos se realiza en paralelo en el lado del servidor.
Generar claves
Las aplicaciones pueden usar la clase KeyFactory
para crear un objeto Key
de una entidad a partir de componentes conocidos, como el tipo y el identificador de la entidad. En el caso de una entidad sin elemento superior, pasa el tipo y el identificador (una cadena de nombre de clave o un ID numérico) al método estático KeyFactory.createKey()
para crear la clave. En los siguientes ejemplos se crea una clave para una entidad de tipo Person
con el nombre de clave "GreatGrandpa"
o el ID numérico 74219
:
Si la clave incluye un componente de ruta, puedes usar la clase de ayuda KeyFactory.Builder
para crear la ruta. El método addChild
de esta clase añade una sola entidad a la ruta y devuelve el propio compilador, por lo que puedes encadenar una serie de llamadas, empezando por la entidad raíz, para crear la ruta de una entidad a la vez. Después de crear la ruta completa, llama a getKey
para obtener la clave resultante:
La clase KeyFactory
también incluye los métodos estáticos keyToString
y stringToKey
para convertir entre claves y sus representaciones de cadena:
La representación de cadena de una clave es "segura para la Web": no contiene caracteres que se consideren especiales en HTML o en URLs.
Usar una lista vacía
Históricamente, Datastore no tenía una representación de una propiedad que representara una lista vacía. El SDK de Java solucionó este problema almacenando colecciones vacías como valores nulos, por lo que no hay forma de distinguir entre valores nulos y listas vacías. Para mantener la retrocompatibilidad, este sigue siendo el comportamiento predeterminado, que se resume de la siguiente manera:- Las propiedades nulas se escriben como nulas en Datastore
- Las colecciones vacías se escriben como nulas en Datastore
- Datastore lee un valor nulo como nulo
- Una colección vacía se lee como nula.
Sin embargo, si cambias el comportamiento predeterminado, el SDK de Java admitirá el almacenamiento de listas vacías. Te recomendamos que tengas en cuenta las implicaciones de cambiar el comportamiento predeterminado de tu aplicación y que actives la compatibilidad con listas vacías.
Para cambiar el comportamiento predeterminado y poder usar listas vacías, define la propiedad DATASTORE_EMPTY_LIST_SUPPORT durante la inicialización de la aplicación de la siguiente manera:
System.setProperty(DatastoreServiceConfig.DATASTORE_EMPTY_LIST_SUPPORT, Boolean.TRUE.toString());
Si esta propiedad tiene el valor true
, como se muestra arriba:
- Las propiedades nulas se escriben como nulas en Datastore
- Las colecciones vacías se escriben como listas vacías en Datastore
- Datastore lee un valor nulo como nulo
- Cuando se lee de Datastore, se devuelve una lista vacía como una colección vacía.