DocumentDB es el servicio NoSQL que nos proporciona Azure como servicio PaaS. Sabemos que las bases de datos NoSQL no tienen esquema y en el caso de DocumentDB guardan su información en formato JSON.
Entonces, si no tenemos esquemas y los datos se guardan en formato JSON ¿Cómo puedo consultar los datos que tengo? La respuesta es mediante lenguaje SQL (Structured Query Language).
En este artículo veremos que sentencias SQL pueden utilizarse y cómo hacerlo.
Esquema de una sentencia SQL en DocumentDB
SELECT [TOP <top_expression>] <select_list>
[FROM <from_sepecification]
[WHERE <filter_condition>}
[ORDER BY <sort_specification>]
Como se puede observar el esquema para realizar consultas es muy familiar si se conoce SQL Cada sentencia consiste en un SELECT acompañado opcionalmente por un FROM, WHERE o ORDER BY. Veamos un ejemplo.
Tenemos la siguiente información en nuestra collection Familias de DocumentDB:
1{2 "id": "FamiliaCompartiMOSS",3 "padres": [4 {5 "apellido": "CompartiMOSS",6 "nombre": "Revista"7 },8 {9 "apellido": "Apellido1",10 "nombre": "Nombre1"11 }12 ],13 "hijos": [14 {15 "apellido": "Apellido2",16 "nombre": "Nombre2",17 "sexo": "mujer",18 "grado": 1,19 "mascotas": [20 {"nombre": "Goofy" },21 {"nombre": "Mickey" }22 ]23 },24 {25 "apellido": "Apellido3",26 "nombre": "Nombre3",27 "sexo": "mujer",28 "grado": 829 }30 ],31 "direccion": {32 "pais": "España",33 "ciudad": "BCN"34 },35 "contacto": {36 "email": "email@email.com",37 "telefono": "000000000"38 },39 "registrado": false40}41
Y realizamos la siguiente consulta:
1 SELECT {2 "Nombre": "f.id",3 "Ciudad": "f.direccion.ciudad"4} AS Familia FROM Familias f WHERE f.direccion.ciudad = “BCN”5
El resultado será:
1[2 {3 "Familia": {4 "Name": "FamiliaCompartiMOSS",5 "Ciudad": "BCN"6 }7 }8]9
Aunque no tengamos un esquema fijo podemos ver cómo podemos realizar consultas utilizando la potencia de SQL. Ahora vamos a ver más en detalle todas las opciones.
FROM
Clausula opcional, aunque si se aplica un filtro en la query o se proyecta algún campo como resultado, entonces será obligatorio definir esta cláusula. Como en una consulta SQL convencional, la cláusula FROM indica la collection sobre la cual se ejecutará la consulta, también puede identificar un subconjunto de la collection como fuente de la consulta.
Un ejemplo de utilización de un subconjunto de la collection sería:
1SELECT *2FROM Familias.hijos3
El resultado será:
1 [2 [3 {4 "apellido": "Apellido2",5 "nombre": "Nombre2",6 "sexo": "mujer",7 "grado": 18 },9 {10 "apellido": "Apellido3",11 "nombre": "Nombre3",12 "sexo": "mujer",13 "grado": 814 }15 ]16]17
También se puede utilizar alias en las consultas de la forma convencional: SELECT f.id FROM Familias AS f. Una vez se utiliza el alias la fuente ya no se reconocerá, es decir, si realizáramos la consulta SELECT Familias id FROM Familias AS f la query no funcionaría, como tampoco funcionaria SELECT id FROM Familias AS f.
Por último, también se puede utilizar la cláusula IN, que nos permite realizar iteraciones sobre JSON arrays. La cláusula FROM nos da soporte para iteraciones. Vamos a ver un ejemplo, cogiendo como base el ejemplo anterior:
1SELECT *2FROM c IN Familias.hijos3El resultado será:45
[ { "apellido": "Apellido2", "nombre": "Nombre2", "sexo": "mujer", "grado": 1 }, { "apellido": "Apellido3", "nombre": "Nombre3", "sexo": "mujer", "grado": 8 } ]
12Podemos ver que al aplicar la cláusula IN, todos los resultados se devuelven en una única lista, mientras que en el primer ejemplo devolvía una lista por resultado.34**WHERE**56El comando WHERE es opcional, y si lo añadimos dentro de una query DocumentDB lo que estamos indicando que condiciones deben satisfacer los resultados que serán incluidos en el resultado de la ejecución.78En el siguiente ejemplo podemos ver como se aplica el operador WHERE:910
SELECT f.direccion FROM Familias f WHERE f.id = "FamiliaCompartiMOSS "
12El resultado será:34
[ { "direccion": { "pais": "España", "ciudad": "BCN" } } ]
12En el ejemplo anterior hemos aplicado el operador =, pero no es el único que podemos utilizar con esta cláusula, también se pueden utilizar los siguientes:34· Aritméticos: +,-,*,/,%5· Lógicos: AND, OR6· Strings: || (concatenación)7· Comparación: =, !=, >, >=, <, <=, <>8· Bits: |, &, ^9· Binarios y unarios: true, false, null, undefined… Un ejemplo de uso de un operador binario sería:1011
SELECT * FROM Familias f WHERE f.registrado
12Esta query nos devolvería todos aquellos documentos que contengan true como valor.34· BETWEEN: Palabra clave que especifica un rango de valores. Puede ser usada con strings o números. Por ejemplo:56
SELECT * FROM Familias.hijos [ 0 ] c WHERE c.grado BETWEEN 1 AND 5
12· IN: Palabra clave que se utiliza para verificar que un valor esté en un conjunto predefinido de valores. Por ejemplo:34
SELECT * FROM Familias WHERE Familias.id IN ('Familia2', 'FamiliaCompartiMOSS')
12**SELECT**34Cualquier consulta sobre DocumentDB debe contener la cláusula SELECT. Esta cláusula nos indica los campos que serán devueltos al ejecutarse la query. Por ejemplo, si queremos devolver solo la dirección ejecutaríamos la siguiente query:56
SELECT f.contacto FROM Familias f WHERE f.id = " FamiliaCompartiMOSS "
12El resultado será:34
[ { "contacto": { "email": "email@email.com", "telefono": "000000000" } } ]
12Dentro del operador SELECT podemos realizar las siguientes operaciones:34· Propiedades Anidadas: Devolver una propiedad que está dentro de otra. Por ejemplo:56
SELECT f.direccion.pais, f.direccion.ciudad FROM Familias f WHERE f.id = " FamiliaCompartiMOSS "
El resultado será:
1[2 {3 "pais": "España",4 "ciudad": "BCN"5 }6]78· Proyecciones: Devolvemos el resultado en una estructura propia.910
SELECT { "pais": "f.direccion.pais", "ciudad": "f.direccion.ciudad", "nombre": "f.id" } FROM Familias f WHERE f.id = " FamiliaCompartiMOSS "
12El resultado será:34
[{ "$1": { "pais": "España", "ciudad": "BCN", "name": " FamiliaCompartiMOSS " } }]
12· Utilización de Alias: Cuando queremos devolver la estructura propia con un nombre propio.34
SELECT { "pais": "f.direccion.pais", "ciudad": "f.direccion.ciudad" } AS DireccionInfo, { "nombre ": f.id } NombreInfo FROM Familias f WHERE f.id = " FamiliaCompartiMOSS "
12El resultado será:34
[{ "DireccionInfo": { "pais": "España", "ciudad": "BCN" }, "NombreInfo": { "nombre": " FamiliaCompartiMOSS " } }]
12· Expresiones escalares: SELECT soporta expresiones del tipo constantes, expresiones aritméticas, lógicas…. Por ejemplo:34
SELECT ((2 + 11 % 7)-2)/3
12El resultado será:34
[ { "$1": 1.33333 } ]
12· VALUE: Es una palabra clave que nos permite devolver un valor. Por ejemplo, si lo quisiéramos devolver una constante:34
SELECT VALUE "CompartiMOSS"
12El resultado será:34
[ "CompartiMOSS" ]
12También nos permitiría eliminar etiquetas de los resultados generados:34
SELECT VALUE f.direccion FROM Familias f
12El resultado será:34
[ { "pais": "España", "ciudad": "BCN" } ]
12· * : Operador especial que nos devolverá todos los campos de la consulta que realicemos:34
SELECT * FROM Familias f WHERE f.id = " FamiliaCompartiMOSS
12El Resultado será:34
[ { "id": "FamiliaCompartiMOSS", "padres": [ { "apellido": "CompartiMOSS", "nombre": "Revista" }, { "apellido": "Apellido1", "nombre": "Nombre1" } ], "hijos": [ { "apellido": "Apellido2", "nombre": "Nombre2", "sexo": "mujer", "grado": 1, "mascotas": [ { "nombre": "Goofy" }, { "nombre": "Mickey" } ] }, { "apellido": "Apellido3", "nombre": "Nombre3", "sexo": "mujer", "grado": 8 } ], "direccion": { "pais": "España", "ciudad": "BCN" }, "contacto": { "email": "email@email.com", "telefono": "000000000" }, ]
12· BETWEEN: Tiene el mismo significado y uso que en el Where.34
SELECT (c.grado BETWEEN 0 AND 10) FROM Familias.hijos [ 0 ] c
12· Operdores ? (Ternary) y ?? (Coalesce): Estos operadores nos permiten aplicar condiciones. Por ejemplo:34
SELECT (c.grado < 5)? "directo": "indirecto" AS nivelgrado FROM Familias.hijos [ 0 ] c
1
SELECT f.nombre ?? f.apellido AS apellido FROM Familias f
12· TOP: Operador que nos permitirá devolver un número concreto de resultados deseados.34
SELECT TOP 1 * FROM Familias f
12El resultado será:34
[ { "id": "FamiliaCompartiMOSS", "padres": [ { "apellido": "CompartiMOSS", "nombre": "Revista" }, { "apellido": "Apellido1", "nombre": "Nombre1" } ], "hijos": [ { "apellido": "Apellido2", "nombre": "Nombre2", "sexo": "mujer", "grado": 1, "mascotas": [ { "nombre": "Goofy" }, { "nombre": "Mickey" } ] }, { "apellido": "Apellido3", "nombre": "Nombre3", "sexo": "mujer", "grado": 8 } ], "direccion": { "pais": "España", "ciudad": "BCN" }, "contacto": { "email": "email@email.com", "telefono": "000000000" }, "registrado": false } ]
12**Arrays y Objetos**34DocumentDB permite la creación de arrays y/o objetos. Podemos construir arrays de la siguiente forma:56
SELECT [ "f.direccion.ciudad", "f.direccion.pais" ] AS PaisCiudad FROM Familias f
12El Resultado será:34
[ { " PaisCiudad ": [ "BCN", "España" ] }, { "CiudadState": [ "BCN", "BCN" ] } ]
12**JOINS**34DocumentDB nos permite realizar JOINS, pero a diferencia del concepto JOIN de una Base de Datos relacional, no nos sirve para relacionar tablas de forma que podamos obtener los datos deseados, sino que nos permite relacionar el schema consigo mismo, lo que en una base de datos relacional equivaldría a realizar una “self-join”.56El resultado de realizar la operación JOIN es un conjunto de N-tuplas con N-Values por tupla, con valores obtenidos de iterar los todos los alias de las collections sobre sus conjuntos.78Por ejemplo, podemos realizar una JOIN entre la raíz y un hijo, el resultado es el producto cruzado entre los dos objetos JSON.910Supongamos que, para este ejemplo, además de la entrada anterior, disponemos de la siguiente entrada1112
{ "id": "FamiliaCompartiMOSS2", "padres": [ { "apellido": "CompartiMOSS22", "nombre": "Revista"2 }, { "apellido": "Apellido12", "nombre": "Nombre12" } ], "hijos": [ { "apellido": "Apellido22", "nombre": "Nombre22", "sexo": "mujer", "grado": 1, "mascotas": [ {"nombre": "Goofy2" }, {"nombre": "Mickey2" } ] ], "direccion": { "pais": "España", "ciudad": "MAD" }, "contacto": { "email": "email2@email.com", "telefono": "000000001" }, "registrado": true }
12Y realizamos la siguiente *query*:34
SELECT f.id FROM Familias f JOIN c IN f.hijos
12El Resultado será:34
[ { "id": " FamiliaCompartiMOSS2" }, { "id": "FamiliaCompartiMOSS" }, { "id": "FamiliaCompartiMOSS" } ]
12ORDER BY34En caso de añadir este operador, nos permitirá ordenar los resultados de la query de la forma deseada, seguimos teniendo las dos entradas en nuestra collection.56
SELECT f.id, f.direccion.ciudad FROM Familias f ORDER BY f.direccion.ciudad
12El Resultado será:34
[ { "id": "FamiliaCompartiMOSS", "ciudad": "BCN" }, { "id": " FamiliaCompartiMOSS2", "ciudad": "MAD" } ]
12CONCLUSIONES34Como podéis observar, realizar queries sobre DobumentDB es muy similar a realizar queries sobre SQL, todos los operadores que tiene son familiares y funcionan de la forma que esperamos. Query playground es un sitio web proporcionado por Microsoft para poder practicar y ver más en profundidad como realizar queries en DobumentDB.56Destacar que DocumentDB también permite trabajar con funciones del tipo:78· Matemático: ABS, CEILING, EXP…..910· Comprobación de tipos: IS\_ARRAY, IS\_BOOL…1112· Funciones de Strings: CONCAT, CONTAINS, ENDSWITH…1314· Funciones de Arrays: ARRAY\_CONCAT, ARRAY\_CONTAINS…1516· Funciones de espacio: ST\_DISTANCE, ST\_WITHIN…1718Para saber más sobre funciones en DocubmentDB, visitar los links del apartado referencias.1920**REFERENCIAS:**2122·23[https://docs.microsoft.com/en-us/azure/documentdb/documentdb-sql-query#built-in-functions](https://docs.microsoft.com/en-us/azure/documentdb/documentdb-sql-query#built-in-functions)2425·26[https://www.documentdb.com/sql/tutorial](https://www.documentdb.com/sql/tutorial)2728· [https://www.documentdb.com/sql/demo](https://www.documentdb.com/sql/demo)29303132**Robert Bermejo**33Arquitecto .Net3435roberto.bermejo@sogeti.com36 @robertbemejo37 www.robertbermejo.com38394041export const _frontmatter = {}42