Nota: Se recomienda encarecidamente a los desarrolladores que creen aplicaciones nuevas que usen la biblioteca de cliente de NDB, que ofrece varias ventajas en comparación con esta biblioteca de cliente, como el almacenamiento automático en caché de entidades mediante la API Memcache. Si actualmente usas la biblioteca de cliente de DB anterior, consulta la guía de migración de DB a NDB.
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 Python App Engine incluye una biblioteca de modelado de datos para representar entidades de Datastore como instancias de clases de Python, así como para almacenar y recuperar esas instancias en Datastore.
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 y a la biblioteca de modelado de datos.
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 Datastore de Python, el tipo de una entidad se determina por su clase de modelo, que se define en la aplicación como una subclase de la clase de biblioteca de modelado de datos db.Model
. El nombre de la clase de modelo se convierte en el tipo de las entidades que pertenecen a ella. 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:
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()
La clase Employee
declara cuatro propiedades para el modelo de datos: first_name
, last_name
, hire_date
y attended_hr_training
. La superclase Model
asegura que los atributos de los objetos Employee
se ajusten a este modelo. Por ejemplo, si se intenta asignar un valor de cadena al atributo hire_date
, se producirá un error de tiempo de ejecución, ya que el modelo de datos de hire_date
se ha declarado como db.DateProperty
.
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 argumento con nombre key_name
al constructor de la clase de modelo al crear la entidad:
# Create an entity with the key Employee:'asalieri'.
employee = Employee(key_name='asalieri')
Para que Datastore asigne un ID numérico automáticamente, omite el argumento key_name
:
# Create an entity with a key such as Employee:8261.
employee = Employee()
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, usa el argumento parent
en el constructor de la clase de modelo al crear la entidad secundaria. El valor de este argumento puede ser la entidad superior o su clave. Para obtener la clave, llama al método key()
de la entidad superior. En el siguiente ejemplo se crea una entidad de tipo Address
y se muestran dos formas de designar una entidad Employee
como su entidad principal:
# 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()
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 | Tipos de Python | Ordenar por | Notas |
---|---|---|---|
Entero | int long |
Numérico | Número entero de 64 bits con signo. |
Número de punto flotante | float |
Numérico | Doble precisión de 64 bits, IEEE 754 |
Booleano | bool |
False <True |
|
Cadena de texto (corta) | str unicode |
Unicode ( str se trata como ASCII) |
Hasta 1500 bytes |
Cadena de texto (larga) | db.Text |
Ninguno | Hasta 1 megabyte Sin indexar |
cadena de bytes (corta) | db.ByteString |
Orden de bytes | Hasta 1500 bytes |
Cadena de bytes (larga) | db.Blob |
Ninguno | Hasta 1 megabyte Sin indexar |
Fecha y hora | datetime.date datetime.time datetime.datetime |
Cronológico | |
Punto geográfico | db.GeoPt |
Por latitud, y luego por longitud |
|
Dirección postal | db.PostalAddress |
Unicode | |
Número de teléfono | db.PhoneNumber |
Unicode | |
Dirección de correo electrónico | db.Email |
Unicode | |
usuarios de Cuentas de Google | users.User |
Dirección de correo electrónico en orden Unicode |
|
Identificador de mensajería instantánea | db.IM |
Unicode | |
Enlace | db.Link |
Unicode | |
Categoría | db.Category |
Unicode | |
Valoración | db.Rating |
Numérico | |
Clave de Datastore | db.Key |
Por elementos de ruta (tipo, identificador, tipo, identificador...) |
|
Clave de Blobstore | blobstore.BlobKey |
Orden de bytes | |
Nulo | NoneType |
Ninguno |
Importante: Te recomendamos que no almacenes un UserProperty
, ya que incluye la dirección de correo y el ID único del usuario. Si un usuario cambia su dirección de correo y comparas el valor antiguo almacenado User
con el nuevo User
, no coincidirán.
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 las cadenas de texto largas y las cadenas de bytes largas no se indexan, 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.
Crear una entidad
En Python, se crea una entidad construyendo una instancia de una clase de modelo, rellenando sus propiedades si es necesario y llamando a su método put()
para guardarla en Datastore. Puedes especificar el nombre de la clave de la entidad pasando un argumento key_name al constructor:
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()
Si no proporcionas un nombre de clave, Datastore generará automáticamente un ID numérico para la clave de la entidad:
employee = Employee(first_name='Antonio',
last_name='Salieri')
employee.hire_date = datetime.datetime.now().date()
employee.attended_hr_training = True
employee.put()
Recuperar una entidad
Para recuperar una entidad identificada por una clave determinada, pasa el objeto Key
como argumento a la función db.get()
. Puede generar el objeto Key
con el método de clase Key.from_path()
.
La ruta completa es una secuencia de entidades de la ruta de ancestros, en la que cada entidad está representada por su tipo (una cadena) seguido de su identificador (nombre de clave o ID numérico):
address_k = db.Key.from_path('Employee', 'asalieri', 'Address', 1)
address = db.get(address_k)
db.get()
devuelve una instancia de la clase de modelo adecuada. Asegúrate de haber importado la clase de modelo de la entidad que se va a recuperar.
Actualizar una entidad
Para actualizar una entidad, modifica los atributos del objeto y, a continuación, llama a su método put()
. Los datos del objeto sobrescriben la entidad existente. El objeto completo se envía a Datastore con cada llamada a put()
.
Para eliminar una propiedad, elimine el atributo del objeto de Python:
del address.postal_code
y, a continuación, guarda el objeto.
Eliminar una entidad
Dada la clave de una entidad, puedes eliminarla con la función db.delete()
.
address_k = db.Key.from_path('Employee', 'asalieri', 'Address', 1)
db.delete(address_k)
o llamando al método delete()
de la entidad:
employee_k = db.Key.from_path('Employee', 'asalieri')
employee = db.get(employee_k)
# ...
employee.delete()
Operaciones por lotes
Las funciones db.put()
, db.get()
y db.delete()
(y sus equivalentes asíncronos db.put_async()
, db.get_async()
y db.delete_async()
) pueden aceptar un argumento de lista para actuar en varias entidades en una sola llamada de 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])
Las operaciones por lotes no modifican tus costes. Se te cobrará por cada clave de una operación por lotes, independientemente de si existe o no. El tamaño de las entidades implicadas en una operación no afecta al coste.
Eliminar entidades en bloque
Si necesitas eliminar un gran número de entidades, te recomendamos que utilices Dataflow para eliminar entidades en bloque.
Usar una lista vacía
En el caso de la interfaz NDB, Datastore escribía históricamente una lista vacía como propiedad omitida tanto para las propiedades estáticas como para las dinámicas. Para mantener la compatibilidad con versiones anteriores, este comportamiento sigue siendo el predeterminado. Para anular este comportamiento de forma global o en cada ListProperty, asigna el valortrue
al argumento write_empty_list de tu clase Property. De este modo, la lista vacía se escribirá en Datastore y se podrá leer como una lista vacía.
En el caso de la interfaz de la base de datos, históricamente no se permitían las escrituras de listas vacías si la propiedad era dinámica: si lo intentabas, se producía un error. Esto significa que no es necesario conservar ningún comportamiento predeterminado para que las propiedades dinámicas de la base de datos sean compatibles con versiones anteriores, por lo que puede escribir y leer la lista vacía en el modelo dinámico sin hacer ningún cambio.
Sin embargo, en el caso de las propiedades estáticas de DB, la lista vacía se escribía como una propiedad omitida y este comportamiento se mantiene de forma predeterminada para mantener la compatibilidad con versiones anteriores.
Si quieres activar las listas vacías para las propiedades estáticas de la base de datos, usa el argumento write_empty_list de true
en tu clase Property. La lista vacía se escribirá en Datastore.