Ya vimos en el post de LuisMi las principales características de esta base de datos de Azure. Hoy desde un punto de vista más práctico, vamos a ver la implementación de la misma en una aplicación Java con Spring Boot, y veremos las ventajas y limitaciones desde el punto de vista del desarrollador. Utilizaremos la API SQL (documental) , aunque ya sabemos que tiene soporte también para MongoDB, Cassandra…
Nota: A día de hoy, azure no permite el uso de diferentes APIs (SQL, Mongo…) sobre la misma base de datos CosmosDB, se tiene que crear una para cada API que se quiera utilizar. Esto se debe a que a la hora de crear la base de datos, en función de la API que se vaya a utilizar, los datos se almacenarán y gestionarán de forma completamente distinta.
Azure facilita una serie de API’s o SDK’s Java SQL diferentes pero con una sintaxis similar:
- (1) Azure DocumentDB API (Sync): SDK Java versión asíncrona. Esta es la API que más tiempo lleva en desarrollo (desde 2015)
- (2) Azure CosmosDB API (Async): SDK Java versión asíncrona.
- (3) Azure CosmosDB API (Sync/Async): en versión beta aún, y es la que utilizan en los «Getting started» de CosmosDB. Es la evolución del SDK DocumentDB
- (4) Azure CosmosDB SpringBoot Starter: librería SpringBoot para utilizarlo a modo de JPA Repositories
¿Qué SDK escogemos?
En el post de hoy, aunque vamos a integrar CosmosDB en una aplicación SpringBoot, hemos optado por no utilizar la librería starter (4), ya que ésta tiene sentido cuando se va a utilizar con un modelo de datos Java. En nuestro caso vamos a trabajar con un modelo de objetos JSON dinámico, por lo que no podemos mapear a POJOs las entidades.
Por lo otro lado, el SDK de CosmosDB (3) más novedoso, trae bastantes incompatibilidades si se utiliza con SpringBoot y Jackson, lo que provoca errores en tiempo de ejecución del tipo ClassDefNotFoundException, NoSuchMethodException, etc. Esto es debido a que utiliza sus propias versiones de las librerías de Jackson para la serialización de objetos, por lo que conseguir la compatibilidad con cierta versión SpringBoot es un trabajo arduo ya de primeras.
Por esta razón decidimos utilizar la API (1), ya que es la más flexible y la más estable para nuestro caso, y tenemos unos requisitos de rendimiento tan críticos como para tener que hacer uso de la API asíncrona.
Cliente CosmosDB
Si seguimos las recomendaciones de desarrollo con el SDK, Azure nos dice que el cliente que utilicemos en nuestra aplicación se registre como Singleton, esto facilita la gestión eficiente de conexiones y el rendimiento del cliente.
Por lo tanto, lo primero será crear una clase de configuración en la que demos de alta el @Bean DocumentClient. Para crear el cliente, le indicaremos el host de nuestra instancia de CosmosDB y la clave maestra, así como el nivel de consistencia (explicado en el post anterior), y la política de conexión del cliente(timeouts, pool, etc).

Creación de base de datos y colecciones/contenedores
Si no hemos creado ya nuestra base de datos, o necesitamos crearla en tiempo de ejecución (p.e. para entornos multitenant, en los que se requiera una base de datos diferente para cada cliente), la operación de creación será tan fácil como:

Una vez tenemos creada la base de datos, podemos empezar a trabajar con los contenedores de CosmosDB, que son el equivalente a las colecciones de MongoDB, de hecho en el SDK de DocumentDB se siguen llamando ‘Collection’.
Para crear una colección, necesitamos indicarle tanto el ID de la colección, como la clave de partición (PK), y las claves únicas (UK) si las hubiera, que permiten añadir una capa de integridad a los datos almacenados.
Tanto las PK como las UK, se definen mediante paths JSON de nuestros documentos. CosmosDB, al igual que otras bases de datos NoSQL, no presenta definición de schemas asociados a las colecciones, y por tanto, si necesitamos gestionar/validar schemas, deberemos hacerlo en otra capa de la aplicación.

Para todas las operaciones sobre colecciones y documentos, CosmosDB necesita el link de referencia, que podrá ser:
- A una base de datos: «/dbs/{databaseId}»
- A una colección : «/dbs/{databaseId}/colls/{collectionId}»
- A una documento : «/dbs/{databaseId}/colls/{collectionId}/docs/{documentId}»
En otras operaciones de consulta además se necesitará indicar el valor de la PK.
CRUD sobre CosmosDB
Para insertar documentos en CosmosDB utilizaremos el método createDocument al que le pasamos el link de referencia a la colección, el JSON serializado mediante la clase Document de la API, y si queremos deshabilitar la generación automática del ID del documento.

Para realizar un update de un documento, necesitamos el link del documento (con su ID correspondiente), y el payload serializado, utilizando el método replaceDocument.

Para realizar un borrado de documento, necesitaremos tanto el ID del documento (para su link), como el valor de la clave de partición. Por esto razón necesitamos hacer un fetch del documento antes de borrarlo, es una de las limitaciones que trae CosmosDB.

En el método estático requestOptions le pasamos el JSON y la PK para extraer del mismo el valor propio de la PK.

Por último, para hacer consultas SELECT SQL, utilizamos el método queryDocuments al que podemos pasarle el valor de la PK para la consulta, o habilitar el atributo enableCrossPartitionQuery en el FeedOptions que le pasamos:


Las queries SQL que soporta CosmosDB, tienen algunas particularidades, por lo que se recomienda leer la documentación facilitada por Azure. Por ejemplo, si utilizamos «LIMIT» debe ir precedido de «OFFSET», si no lanzará una excepción.
En el siguiente post del blog, completaremos el tema con: operaciones en Bulk, limitaciones, e implementación de UPDATE y DELETE en SQL.