DocumentDB - Guía rápida
En este capítulo, discutiremos brevemente los conceptos principales sobre NoSQL y bases de datos de documentos. También tendremos una descripción general rápida de DocumentDB.
Base de datos de documentos NoSQL
DocumentDB es la base de datos de documentos NoSQL más nueva de Microsoft, por lo que cuando dice base de datos de documentos NoSQL, ¿qué queremos decir exactamente con NoSQL y base de datos de documentos?
SQL significa lenguaje de consulta estructurado, que es el lenguaje de consulta tradicional de las bases de datos relacionales. SQL se equipara a menudo con bases de datos relacionales.
Es realmente más útil pensar en una base de datos NoSQL como una base de datos no relacional, por lo que NoSQL realmente significa no relacional.
Hay diferentes tipos de bases de datos NoSQL que incluyen almacenes de valores clave como:
- Almacenamiento de tablas de Azure.
- Tiendas basadas en columnas como Cassandra.
- Grafique bases de datos como NEO4.
- Documente bases de datos como MongoDB y Azure DocumentDB.
Azure DocumentDB
Microsoft lanzó oficialmente Azure DocumentDB de abril 8 ª de 2015, y que sin duda puede ser caracterizado como una base de datos NoSQL típica documento. Es enormemente escalable y funciona con documentos JSON sin esquema.
DocumentDB es un verdadero servicio de base de datos de documentos NoSQL sin esquemas diseñado para aplicaciones móviles y web modernas.
También ofrece lecturas y escrituras consistentemente rápidas, flexibilidad de esquema y la capacidad de escalar fácilmente una base de datos hacia arriba y hacia abajo bajo demanda.
No asume ni requiere ningún esquema para los documentos JSON que indexa.
DocumentDB indexa automáticamente todas las propiedades de un documento tan pronto como el documento se agrega a la base de datos.
DocumentDB permite consultas complejas ad-hoc utilizando un lenguaje SQL, y cada documento se puede consultar instantáneamente en el momento en que se crea, y puede buscar en cualquier propiedad en cualquier lugar dentro de la jerarquía del documento.
DocumentDB - Precios
DocumentDB se factura en función del número de colecciones contenidas en una cuenta de base de datos. Cada cuenta puede tener una o más bases de datos y cada base de datos puede tener un número virtualmente ilimitado de colecciones, aunque hay una cuota predeterminada inicial de 100. Esta cuota se puede levantar poniéndose en contacto con el soporte de Azure.
Una colección no es solo una unidad de escala, sino también una unidad de costo, por lo que en DocumentDB pagas por colección, que tiene una capacidad de almacenamiento de hasta 10 GB.
Como mínimo, necesitará una colección S1 para almacenar documentos en una base de datos que costará aproximadamente $ 25 por mes, que se factura a su suscripción de Azure.
A medida que su base de datos crece en tamaño y supera los 10 GB, deberá comprar otra colección para contener los datos adicionales.
Cada colección de S1 le dará 250 unidades de solicitud por segundo y, si eso no es suficiente, puede escalar la colección a S2 y obtener 1000 unidades de solicitud por segundo por aproximadamente $ 50 al mes.
También puede convertirlo en un S3 y pagar alrededor de $ 100 al mes.
DocumentDB se destaca con algunas capacidades únicas. Azure DocumentDB ofrece las siguientes funciones y ventajas clave.
Sin esquema
En una base de datos relacional, cada tabla tiene un esquema que define las columnas y los tipos de datos que debe cumplir cada fila de la tabla.
Por el contrario, una base de datos de documentos no tiene un esquema definido y cada documento puede estructurarse de manera diferente.
Sintaxis SQL
DocumentDB permite consultas complejas ad-hoc utilizando lenguaje SQL, y cada documento se puede consultar instantáneamente en el momento en que se crea. Puede buscar en cualquier propiedad en cualquier lugar dentro de la jerarquía del documento.
Consistencia sintonizable
Proporciona algunos niveles de consistencia granulares y bien definidos, lo que le permite hacer concesiones sólidas entre consistencia, disponibilidad y latencia.
Puede seleccionar entre cuatro niveles de consistencia bien definidos para lograr un equilibrio óptimo entre consistencia y rendimiento. Para consultas y operaciones de lectura, DocumentDB ofrece cuatro niveles de coherencia distintos:
- Strong
- Bounded-staleness
- Session
- Eventual
Escala elástica
La escalabilidad es el nombre del juego con NoSQL, y DocumentDB cumple. DocumentDB ya ha demostrado su escala.
Los principales servicios como Office OneNote y Xbox ya están respaldados por DocumentDB con bases de datos que contienen decenas de terabytes de documentos JSON, más de un millón de usuarios activos y que operan de manera consistente con una disponibilidad del 99,95%.
Puede escalar elásticamente DocumentDB con un rendimiento predecible creando más unidades a medida que crece su aplicación.
Totalmente administrado
DocumentDB está disponible como una plataforma basada en la nube totalmente administrada como un servicio que se ejecuta en Azure.
Simplemente no hay nada que instalar o administrar.
No hay servidores, cables, sistemas operativos o actualizaciones con los que lidiar, ni réplicas que configurar.
Microsoft hace todo ese trabajo y mantiene el servicio en funcionamiento.
En literalmente minutos, puede comenzar a trabajar con DocumentDB usando solo un navegador y una suscripción de Azure.
Microsoft proporciona una versión gratuita de Visual Studio que también contiene SQL Server y se puede descargar desde https://www.visualstudio.com
Instalación
Step 1- Una vez completada la descarga, ejecute el instalador. Se mostrará el siguiente cuadro de diálogo.
Step 2 - Haga clic en el botón Instalar y comenzará el proceso de instalación.
Step 3 - Una vez que el proceso de instalación se haya completado con éxito, verá el siguiente cuadro de diálogo.
Step 4 - Cierre este cuadro de diálogo y reinicie su computadora si es necesario.
Step 5- Ahora abra Visual Studio desde el menú de inicio, que abrirá el siguiente cuadro de diálogo. Tomará algún tiempo por primera vez solo para la preparación.
Una vez hecho todo, verá la ventana principal de Visual Studio.
Step 6 - Creemos un nuevo proyecto desde Archivo → Nuevo → Proyecto.
Step 7 - Seleccione Aplicación de consola, ingrese DocumentDBDemo en el campo Nombre y haga clic en el botón Aceptar.
Step 8 - En el Explorador de soluciones, haga clic con el botón derecho en su proyecto.
Step 9 - Seleccione Administrar paquetes NuGet que abrirá la siguiente ventana en Visual Studio y en el cuadro de entrada Buscar en línea, busque la biblioteca cliente de DocumentDB.
Step 10 - Instale la última versión haciendo clic en el botón de instalación.
Step 11- Haga clic en "Acepto". Una vez finalizada la instalación, verá el mensaje en la ventana de salida.
Ahora está listo para iniciar su aplicación.
Para utilizar Microsoft Azure DocumentDB, debe crear una cuenta de DocumentDB. En este capítulo, crearemos una cuenta de DocumentDB utilizando Azure Portal.
Step 1 - Inicie sesión en línea https://portal.azure.com si ya tiene una suscripción de Azure, de lo contrario, primero debe iniciar sesión.
Verá el panel principal. Es totalmente personalizable, por lo que puede organizar estos mosaicos de la forma que desee, cambiar su tamaño, agregar y eliminar mosaicos para las cosas que usa con frecuencia o que ya no hace.
Step 2 - Seleccione la opción 'Nuevo' en la parte superior izquierda de la página.
Step 3 - Ahora seleccione la opción Datos + Almacenamiento> Azure DocumentDB y verá la siguiente sección Nueva cuenta de DocumentDB.
Necesitamos encontrar un nombre (ID) único a nivel mundial, que combinado con .documents.azure.com es el punto final públicamente direccionable para nuestra cuenta de DocumentDB. Se puede acceder a todas las bases de datos que creamos debajo de esa cuenta a través de Internet utilizando este punto final.
Step 4 - Vamos a nombrarlo azuredocdbdemo y hagamos clic en Grupo de recursos → new_resource.
Step 5- Elija la ubicación, es decir, en qué centro de datos de Microsoft desea que se aloje esta cuenta. Seleccione la ubicación y elija su región.
Step 6 - Marque la casilla de verificación Pin en el panel de control y siga adelante y haga clic en el botón Crear.
Puede ver que el mosaico ya se agregó al Panel de control y nos informa que se está creando la cuenta. En realidad, puede llevar unos minutos configurar las cosas para una nueva cuenta mientras DocumentDB asigna el punto final, aprovisiona réplicas y realiza otros trabajos en segundo plano.
Una vez hecho esto, verá el tablero.
Step 7 - Ahora haga clic en la cuenta DocumentDB creada y verá una pantalla detallada como la siguiente imagen.
Cuando comienzas a programar con DocumentDB, el primer paso es conectarte. Entonces, para conectarse a su cuenta de DocumentDB, necesitará dos cosas;
- Endpoint
- Clave de autorización
Punto final
Endpoint es la URL de su cuenta de DocumentDB y se construye combinando su nombre de cuenta de DocumentDB con .documents.azure.com. Vayamos al Tablero.
Ahora, haga clic en la cuenta DocumentDB creada. Verá los detalles como se muestra en la siguiente imagen.
Cuando seleccione la opción 'Claves', mostrará información adicional como se muestra en la siguiente imagen. También verá la URL de su cuenta de DocumentDB, que puede usar como su punto final.
Clave de autorización
La clave de autorización contiene sus credenciales y hay dos tipos de claves. La clave maestra permite el acceso completo a todos los recursos dentro de la cuenta, mientras que los tokens de recursos permiten el acceso restringido a recursos específicos.
Llaves maestras
No hay nada que no puedas hacer con una llave maestra. Puede destruir toda su base de datos si lo desea, utilizando la clave maestra.
Por esta razón, definitivamente no desea compartir la clave maestra o distribuirla a entornos de cliente. Como medida de seguridad adicional, es una buena idea cambiarlo con frecuencia.
En realidad, hay dos claves maestras para cada cuenta de base de datos, la principal y la secundaria, como se resalta en la captura de pantalla anterior.
Tokens de recursos
También puede utilizar tokens de recursos en lugar de una clave maestra.
Las conexiones basadas en tokens de recursos solo pueden acceder a los recursos especificados por los tokens y no a otros recursos.
Los tokens de recursos se basan en los permisos de usuario, por lo que primero crea uno o más usuarios, y estos se definen a nivel de la base de datos.
Usted crea uno o más permisos para cada usuario, en función de los recursos a los que desea permitir que cada usuario acceda.
Cada permiso genera un token de recurso que permite el acceso completo o de solo lectura a un recurso determinado y que puede ser cualquier recurso de usuario dentro de la base de datos.
Vayamos a la aplicación de consola creada en el capítulo 3.
Step 1 - Agregue las siguientes referencias en el archivo Program.cs.
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using Newtonsoft.Json;
Step 2- Ahora agregue la URL del extremo y la clave de autorización. En este ejemplo, usaremos la clave principal como clave de autorización.
Tenga en cuenta que, en su caso, tanto la URL del punto final como la clave de autorización deben ser diferentes.
private const string EndpointUrl = "https://azuredocdbdemo.documents.azure.com:443/";
private const string AuthorizationKey =
"BBhjI0gxdVPdDbS4diTjdloJq7Fp4L5RO/StTt6UtEufDM78qM2CtBZWbyVwFPSJIm8AcfDu2O+AfV T+TYUnBQ==";
Step 3 - Cree una nueva instancia de DocumentClient en una tarea asincrónica llamada CreateDocumentClient y cree una nueva instancia de DocumentClient.
Step 4 - Llame a su tarea asincrónica desde su método Main.
A continuación se muestra el archivo Program.cs completo hasta ahora.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using Newtonsoft.Json;
namespace DocumentDBDemo {
class Program {
private const string EndpointUrl = "https://azuredocdbdemo.documents.azure.com:443/";
private const string AuthorizationKey = "BBhjI0gxdVPdDbS4diTjdloJq7Fp4L5RO/
StTt6UtEufDM78qM2CtBZWbyVwFPSJIm8AcfDu2O+AfV T+TYUnBQ==";
static void Main(string[] args) {
try {
CreateDocumentClient().Wait();
} catch (Exception e) {
Exception baseException = e.GetBaseException();
Console.WriteLine("Error: {0}, Message: {1}", e.Message, baseException.Message);
}
Console.ReadKey();
}
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey);
}
}
}
En este capítulo, hemos aprendido cómo conectarnos a una cuenta de DocumentDB y crear una instancia de la clase DocumentClient.
En este capítulo, aprenderemos cómo crear una base de datos. Para usar Microsoft Azure DocumentDB, debe tener una cuenta de DocumentDB, una base de datos, una colección y documentos. Ya tenemos una cuenta de DocumentDB, ahora para crear una base de datos tenemos dos opciones -
- Portal de Microsoft Azure o
- .Net SDK
Cree una base de datos para DocumentDB utilizando el portal de Microsoft Azure
Para crear una base de datos usando el portal, los siguientes son los pasos.
Step 1 - Inicie sesión en Azure Portal y verá el panel.
Step 2 - Ahora haga clic en la cuenta de DocumentDB creada y verá los detalles como se muestra en la siguiente captura de pantalla.
Step 3 - Seleccione la opción Agregar base de datos y proporcione el ID de su base de datos.
Step 4 - Haga clic en Aceptar.
Puede ver que se agrega la base de datos. Por el momento, no tiene colección, pero podemos agregar colecciones más adelante que son los contenedores que almacenarán nuestros documentos JSON. Tenga en cuenta que tiene tanto un ID como un ID de recurso.
Cree una base de datos para DocumentDB con .Net SDK
Para crear una base de datos usando .Net SDK, los siguientes son los pasos.
Step 1 - Abra la aplicación de consola en Visual Studio del último capítulo.
Step 2- Cree la nueva base de datos creando un nuevo objeto de base de datos. Para crear una nueva base de datos, solo necesitamos asignar la propiedad Id, que estamos configurando en "mynewdb" en una tarea CreateDatabase.
private async static Task CreateDatabase(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("******** Create Database *******");
var databaseDefinition = new Database { Id = "mynewdb" };
var result = await client.CreateDatabaseAsync(databaseDefinition);
var database = result.Resource;
Console.WriteLine(" Database Id: {0}; Rid: {1}", database.Id, database.ResourceId);
Console.WriteLine("******** Database Created *******");
}
Step 3- Ahora pase esta databaseDefinition a CreateDatabaseAsync y obtenga un resultado con una propiedad Resource. Todos los métodos de creación de objeto devuelven una propiedad de recurso que describe el elemento que se creó, que en este caso es una base de datos.
Obtenemos el nuevo objeto de base de datos de la propiedad Resource y se muestra en la consola junto con el ID de recurso que le asignó DocumentDB.
Step 4 - Ahora llame a la tarea CreateDatabase desde la tarea CreateDocumentClient después de crear una instancia de DocumentClient.
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
await CreateDatabase(client);
}
A continuación se muestra el archivo Program.cs completo hasta ahora.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using Newtonsoft.Json;
namespace DocumentDBDemo {
class Program {
private const string EndpointUrl = "https://azuredocdbdemo.documents.azure.com:443/";
private const string AuthorizationKey = "BBhjI0gxdVPdDbS4diTjdloJq7Fp4L5RO/
StTt6UtEufDM78qM2CtBZWbyVwFPSJIm8AcfDu2O+AfV T+TYUnBQ==";
static void Main(string[] args) {
try {
CreateDocumentClient().Wait();
} catch (Exception e) {
Exception baseException = e.GetBaseException();
Console.WriteLine("Error: {0}, Message: {1}", e.Message, baseException.Message);
}
Console.ReadKey();
}
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
await CreateDatabase(client);
}
}
private async static Task CreateDatabase(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("******** Create Database *******");
var databaseDefinition = new Database { Id = "mynewdb" };
var result = await client.CreateDatabaseAsync(databaseDefinition);
var database = result.Resource;
Console.WriteLine(" Database Id: {0}; Rid: {1}", database.Id, database.ResourceId);
Console.WriteLine("******** Database Created *******");
}
}
}
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado que contiene los ID de la base de datos y los recursos.
******** Create Database *******
Database Id: mynewdb; Rid: ltpJAA==
******** Database Created *******
Hasta ahora, hemos creado dos bases de datos en nuestra cuenta de DocumentDB, la primera se crea usando Azure Portal mientras que la segunda base de datos se crea usando .Net SDK. Ahora, para ver estas bases de datos, puede usar Azure Portal.
Vaya a su cuenta de DocumentDB en Azure Portal y verá dos bases de datos ahora.
También puede ver o enumerar las bases de datos de su código utilizando .Net SDK. Los siguientes son los pasos involucrados.
Step 1 - Emitir una consulta de base de datos sin parámetros que devuelve una lista completa, pero también puede pasar una consulta para buscar una base de datos específica o bases de datos específicas.
private static void GetDatabases(DocumentClient client) {
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("******** Get Databases List ********");
var databases = client.CreateDatabaseQuery().ToList();
foreach (var database in databases) {
Console.WriteLine(" Database Id: {0}; Rid: {1}", database.Id, database.ResourceId);
}
Console.WriteLine();
Console.WriteLine("Total databases: {0}", databases.Count);
}
Verá que hay muchos de estos métodos CreateQuery para localizar colecciones, documentos, usuarios y otros recursos. Estos métodos en realidad no ejecutan la consulta, simplemente definen la consulta y devuelven un objeto iterable.
Es la llamada a ToList () la que realmente ejecuta la consulta, itera los resultados y los devuelve en una lista.
Step 2 - Llame al método GetDatabases desde la tarea CreateDocumentClient después de crear una instancia de DocumentClient.
Step 3 - También debe comentar la tarea CreateDatabase o cambiar la identificación de la base de datos; de lo contrario, recibirá un mensaje de error de que la base de datos existe.
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
//await CreateDatabase(client);
GetDatabases(client);
}
A continuación se muestra el archivo Program.cs completo hasta ahora.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using Newtonsoft.Json;
namespace DocumentDBDemo {
class Program {
private const string EndpointUrl = "https://azuredocdbdemo.documents.azure.com:443/";
private const string AuthorizationKey = "BBhjI0gxdVPdDbS4diTjdloJq7Fp4L5RO/
StTt6UtEufDM78qM2CtBZWbyVwFPSJIm8AcfDu2O+AfV T+TYUnBQ==";
static void Main(string[] args) {
try {
CreateDocumentClient().Wait();
} catch (Exception e) {
Exception baseException = e.GetBaseException();
Console.WriteLine("Error: {0}, Message: {1}", e.Message, baseException.Message);
}
Console.ReadKey();
}
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
await CreateDatabase(client);
GetDatabases(client);
}
}
private async static Task CreateDatabase(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("******** Create Database *******");
var databaseDefinition = new Database { Id = "mynewdb" };
var result = await client.CreateDatabaseAsync(databaseDefinition);
var database = result.Resource;
Console.WriteLine(" Database Id: {0}; Rid: {1}", database.Id, database.ResourceId);
Console.WriteLine("******** Database Created *******");
}
private static void GetDatabases(DocumentClient client) {
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("******** Get Databases List ********");
var databases = client.CreateDatabaseQuery().ToList();
foreach (var database in databases) {
Console.WriteLine(" Database Id: {0}; Rid: {1}",
database.Id, database.ResourceId);
}
Console.WriteLine();
Console.WriteLine("Total databases: {0}", databases.Count);
}
}
}
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado que contiene los ID de la base de datos y los recursos de ambas bases de datos. Al final, también verá el número total de bases de datos.
******** Get Databases List ********
Database Id: myfirstdb; Rid: Ic8LAA==
Database Id: mynewdb; Rid: ltpJAA==
Total databases: 2
Puede eliminar una base de datos o bases de datos desde el portal así como desde el código utilizando .Net SDK. Aquí, discutiremos, paso a paso, cómo eliminar una base de datos en DocumentDB.
Step 1- Vaya a su cuenta de DocumentDB en Azure Portal. Para fines de demostración, agregué dos bases de datos más como se ve en la siguiente captura de pantalla.
Step 2- Para eliminar cualquier base de datos, debe hacer clic en esa base de datos. Seleccionemos tempdb, verá la siguiente página, seleccione la opción 'Eliminar base de datos'.
Step 3 - Mostrará el mensaje de confirmación, ahora haga clic en el botón 'Sí'.
Verá que tempdb ya no está disponible en su tablero.
También puede eliminar bases de datos de su código utilizando .Net SDK. Para hacer los siguientes son los pasos.
Step 1 - Eliminemos la base de datos especificando el ID de la base de datos que queremos eliminar, pero necesitamos su SelfLink.
Step 2 - Estamos llamando a CreateDatabaseQuery como antes, pero esta vez en realidad estamos proporcionando una consulta para devolver solo la base de datos con el ID tempdb1.
private async static Task DeleteDatabase(DocumentClient client) {
Console.WriteLine("******** Delete Database ********");
Database database = client
.CreateDatabaseQuery("SELECT * FROM c WHERE c.id = 'tempdb1'")
.AsEnumerable()
.First();
await client.DeleteDatabaseAsync(database.SelfLink);
}
Step 3- Esta vez, podemos llamar a AsEnumerable en lugar de ToList () porque en realidad no necesitamos un objeto de lista. Esperando solo el resultado, llamar a AsEnumerable es suficiente para que podamos obtener el primer objeto de base de datos devuelto por la consulta con First (). Este es el objeto de base de datos para tempdb1 y tiene un SelfLink que podemos usar para llamar a DeleteDatabaseAsync que borra la base de datos.
Step 4 - También debe llamar a la tarea DeleteDatabase desde la tarea CreateDocumentClient después de crear una instancia de DocumentClient.
Step 5 - Para ver la lista de bases de datos después de eliminar la base de datos especificada, llamemos nuevamente al método GetDatabases.
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
//await CreateDatabase(client);
GetDatabases(client);
await DeleteDatabase(client);
GetDatabases(client);
}
A continuación se muestra el archivo Program.cs completo hasta ahora.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using Newtonsoft.Json;
namespace DocumentDBDemo {
class Program {
private const string EndpointUrl = "https://azuredocdbdemo.documents.azure.com:443/";
private const string AuthorizationKey = "BBhjI0gxdVPdDbS4diTjdloJq7Fp4L5RO/
StTt6UtEufDM78qM2CtBZWbyVwFPSJIm8AcfDu2O+AfV T+TYUnBQ==";
static void Main(string[] args) {
try {
CreateDocumentClient().Wait();
} catch (Exception e) {
Exception baseException = e.GetBaseException();
Console.WriteLine("Error: {0}, Message: {1}", e.Message, baseException.Message);
}
Console.ReadKey();
}
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
//await CreateDatabase(client);
GetDatabases(client);
await DeleteDatabase(client);
GetDatabases(client);
}
}
private async static Task CreateDatabase(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("******** Create Database *******");
var databaseDefinition = new Database { Id = "mynewdb" };
var result = await client.CreateDatabaseAsync(databaseDefinition);
var database = result.Resource;
Console.WriteLine(" Database Id: {0}; Rid: {1}",
database.Id, database.ResourceId);
Console.WriteLine("******** Database Created *******");
}
private static void GetDatabases(DocumentClient client) {
Console.WriteLine();
Console.WriteLine();
Console.WriteLine("******** Get Databases List ********");
var databases = client.CreateDatabaseQuery().ToList();
foreach (var database in databases) {
Console.WriteLine(" Database Id: {0}; Rid: {1}", database.Id,
database.ResourceId);
}
Console.WriteLine();
Console.WriteLine("Total databases: {0}", databases.Count);
}
private async static Task DeleteDatabase(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("******** Delete Database ********");
Database database = client
.CreateDatabaseQuery("SELECT * FROM c WHERE c.id = 'tempdb1'")
.AsEnumerable()
.First();
await client.DeleteDatabaseAsync(database.SelfLink);
}
}
}
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado que contiene los ID de base de datos y recursos de las tres bases de datos y el número total de bases de datos.
******** Get Databases List ********
Database Id: myfirstdb; Rid: Ic8LAA==
Database Id: mynewdb; Rid: ltpJAA==
Database Id: tempdb1; Rid: 06JjAA==
Total databases: 3
******** Delete Database ********
******** Get Databases List ********
Database Id: myfirstdb; Rid: Ic8LAA==
Database Id: mynewdb; Rid: ltpJAA==
Total databases: 2
Después de eliminar la base de datos, también verá al final que solo quedan dos bases de datos en la cuenta de DocumentDB.
En este capítulo, aprenderemos cómo crear una colección. Es similar a crear una base de datos. Puede crear una colección desde el portal o desde el código utilizando .Net SDK.
Step 1 - Vaya al panel principal de Azure Portal.
Step 2 - Seleccione myfirstdb de la lista de bases de datos.
Step 3- Haga clic en la opción 'Agregar colección' y especifique el ID de la colección. Seleccione el nivel de precios para una opción diferente.
Step 4 - Seleccionemos S1 Standard y hagamos clic en el botón Seleccionar → Aceptar.
Como puede ver, MyCollection se agrega a myfirstdb.
También puede crear una colección a partir del código utilizando .Net SDK. Echemos un vistazo a los siguientes pasos para agregar colecciones desde el código.
Step 1 - Abra la aplicación de consola en Visual Studio.
Step 2 - Para crear una colección, primero recupere la base de datos myfirstdb por su ID en la tarea CreateDocumentClient.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'myfirstdb'").AsEnumerable().First();
await CreateCollection(client, "MyCollection1");
await CreateCollection(client, "MyCollection2", "S2");
}
}
A continuación se muestra la implementación de la tarea CreateCollection.
private async static Task CreateCollection(DocumentClient client, string collectionId,
string offerType = "S1") {
Console.WriteLine();
Console.WriteLine("**** Create Collection {0} in {1} ****", collectionId, database.Id);
var collectionDefinition = new DocumentCollection { Id = collectionId };
var options = new RequestOptions { OfferType = offerType };
var result = await client.CreateDocumentCollectionAsync(database.SelfLink,
collectionDefinition, options);
var collection = result.Resource;
Console.WriteLine("Created new collection");
ViewCollection(collection);
}
Creamos un nuevo objeto DocumentCollection que define la nueva colección con el Id deseado para el método CreateDocumentCollectionAsync que también acepta un parámetro de opciones que estamos usando aquí para establecer el nivel de rendimiento de la nueva colección, que llamamos offerType.
Este valor predeterminado es S1 y, dado que no pasamos un offerType, para MyCollection1, esta será una colección S1 y para MyCollection2 hemos pasado S2, lo que hace que este sea un S2 como se muestra arriba.
A continuación se muestra la implementación del método ViewCollection.
private static void ViewCollection(DocumentCollection collection) {
Console.WriteLine("Collection ID: {0} ", collection.Id);
Console.WriteLine("Resource ID: {0} ", collection.ResourceId);
Console.WriteLine("Self Link: {0} ", collection.SelfLink);
Console.WriteLine("Documents Link: {0} ", collection.DocumentsLink);
Console.WriteLine("UDFs Link: {0} ", collection.UserDefinedFunctionsLink);
Console.WriteLine(" StoredProcs Link: {0} ", collection.StoredProceduresLink);
Console.WriteLine("Triggers Link: {0} ", collection.TriggersLink);
Console.WriteLine("Timestamp: {0} ", collection.Timestamp);
}
A continuación se muestra la implementación completa del archivo program.cs para colecciones.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using Newtonsoft.Json;
namespace DocumentDBDemo {
class Program {
private const string EndpointUrl = "https://azuredocdbdemo.documents.azure.com:443/";
private const string AuthorizationKey = "BBhjI0gxdVPdDbS4diTjdloJq7Fp4L5RO/
StTt6UtEufDM78qM2CtBZWbyVwFPSJIm8AcfDu2O+AfV T+TYUnBQ==";
private static Database database;
static void Main(string[] args) {
try {
CreateDocumentClient().Wait();
} catch (Exception e) {
Exception baseException = e.GetBaseException();
Console.WriteLine("Error: {0}, Message: {1}", e.Message, baseException.Message);
}
Console.ReadKey();
}
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'myfirstdb'").AsEnumerable().First();
await CreateCollection(client, "MyCollection1");
await CreateCollection(client, "MyCollection2", "S2");
//await CreateDatabase(client);
//GetDatabases(client);
//await DeleteDatabase(client);
//GetDatabases(client);
}
}
private async static Task CreateCollection(DocumentClient client,
string collectionId, string offerType = "S1") {
Console.WriteLine();
Console.WriteLine("**** Create Collection {0} in {1} ****", collectionId,
database.Id);
var collectionDefinition = new DocumentCollection { Id = collectionId };
var options = new RequestOptions { OfferType = offerType };
var result = await
client.CreateDocumentCollectionAsync(database.SelfLink,
collectionDefinition, options);
var collection = result.Resource;
Console.WriteLine("Created new collection");
ViewCollection(collection);
}
private static void ViewCollection(DocumentCollection collection) {
Console.WriteLine("Collection ID: {0} ", collection.Id);
Console.WriteLine("Resource ID: {0} ", collection.ResourceId);
Console.WriteLine("Self Link: {0} ", collection.SelfLink);
Console.WriteLine("Documents Link: {0} ", collection.DocumentsLink);
Console.WriteLine("UDFs Link: {0} ", collection.UserDefinedFunctionsLink);
Console.WriteLine("StoredProcs Link: {0} ", collection.StoredProceduresLink);
Console.WriteLine("Triggers Link: {0} ", collection.TriggersLink);
Console.WriteLine("Timestamp: {0} ", collection.Timestamp);
}
}
}
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado que contiene toda la información relacionada con la recopilación.
**** Create Collection MyCollection1 in myfirstdb ****
Created new collection
Collection ID: MyCollection1
Resource ID: Ic8LAPPvnAA=
Self Link: dbs/Ic8LAA==/colls/Ic8LAPPvnAA=/
Documents Link: dbs/Ic8LAA==/colls/Ic8LAPPvnAA=/docs/
UDFs Link: dbs/Ic8LAA==/colls/Ic8LAPPvnAA=/udfs/
StoredProcs Link: dbs/Ic8LAA==/colls/Ic8LAPPvnAA=/sprocs/
Triggers Link: dbs/Ic8LAA==/colls/Ic8LAPPvnAA=/triggers/
Timestamp: 12/10/2015 4:55:36 PM
**** Create Collection MyCollection2 in myfirstdb ****
Created new collection
Collection ID: MyCollection2
Resource ID: Ic8LAKGHDwE=
Self Link: dbs/Ic8LAA==/colls/Ic8LAKGHDwE=/
Documents Link: dbs/Ic8LAA==/colls/Ic8LAKGHDwE=/docs/
UDFs Link: dbs/Ic8LAA==/colls/Ic8LAKGHDwE=/udfs/
StoredProcs Link: dbs/Ic8LAA==/colls/Ic8LAKGHDwE=/sprocs/
Triggers Link: dbs/Ic8LAA==/colls/Ic8LAKGHDwE=/triggers/
Timestamp: 12/10/2015 4:55:38 PM
Para eliminar colecciones o colecciones, puede hacer lo mismo desde el portal y desde el código utilizando .Net SDK.
Step 1- Vaya a su cuenta de DocumentDB en Azure Portal. Para fines de demostración, agregué dos colecciones más, como se ve en la siguiente captura de pantalla.
Step 2- Para eliminar cualquier colección, debe hacer clic en esa colección. Seleccionemos TempCollection1. Verá la siguiente página, seleccione la opción 'Eliminar colección'.
Step 3- Mostrará el mensaje de confirmación. Ahora haga clic en el botón 'Sí'.
Verá que TempCollection1 ya no está disponible en su tablero.
También puede eliminar colecciones de su código utilizando .Net SDK. Para hacer eso, siga los siguientes pasos.
Step 1 - Eliminemos la colección especificando el ID de la colección que queremos eliminar.
Es el patrón habitual de consulta por Id para obtener los autoenlaces necesarios para eliminar un recurso.
private async static Task DeleteCollection(DocumentClient client, string collectionId) {
Console.WriteLine();
Console.WriteLine("**** Delete Collection {0} in {1} ****", collectionId, database.Id);
var query = new SqlQuerySpec {
QueryText = "SELECT * FROM c WHERE c.id = @id",
Parameters = new SqlParameterCollection {
new SqlParameter {
Name = "@id", Value = collectionId
}
}
};
DocumentCollection collection = client.CreateDocumentCollectionQuery(database.SelfLink,
query).AsEnumerable().First();
await client.DeleteDocumentCollectionAsync(collection.SelfLink);
Console.WriteLine("Deleted collection {0} from database {1}", collectionId,
database.Id);
}
Aquí vemos la forma preferida de construir una consulta parametrizada. No estamos codificando el ID de colección, por lo que este método se puede usar para eliminar cualquier colección. Estamos solicitando una colección específica por Id donde el parámetro Id está definido en este SqlParameterCollection asignado a la propiedad del parámetro de este SqlQuerySpec.
Luego, el SDK hace el trabajo de construir la cadena de consulta final para DocumentDB con el collectionId incrustado en su interior.
Step 2 - Ejecute la consulta y luego use su SelfLink para eliminar la colección de la tarea CreateDocumentClient.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'myfirstdb'").AsEnumerable().First();
await DeleteCollection(client, "TempCollection");
}
}
A continuación se muestra la implementación completa del archivo Program.cs.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using Newtonsoft.Json;
namespace DocumentDBDemo {
class Program {
private const string EndpointUrl = "https://azuredocdbdemo.documents.azure.com:443/";
private const string AuthorizationKey = "BBhjI0gxdVPdDbS4diTjdloJq7Fp4L5RO/
StTt6UtEufDM78qM2CtBZWbyVwFPSJIm8AcfDu2O+AfV T+TYUnBQ==";
private static Database database;
static void Main(string[] args) {
try {
CreateDocumentClient().Wait();
} catch (Exception e) {
Exception baseException = e.GetBaseException();
Console.WriteLine("Error: {0}, Message: {1}", e.Message, baseException.Message);
}
Console.ReadKey();
}
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'myfirstdb'").AsEnumerable().First();
await DeleteCollection(client, "TempCollection");
//await CreateCollection(client, "MyCollection1");
//await CreateCollection(client, "MyCollection2", "S2");
////await CreateDatabase(client);
//GetDatabases(client);
//await DeleteDatabase(client);
//GetDatabases(client);
}
}
private async static Task CreateCollection(DocumentClient client,
string collectionId, string offerType = "S1") {
Console.WriteLine();
Console.WriteLine("**** Create Collection {0} in {1} ****", collectionId,
database.Id);
var collectionDefinition = new DocumentCollection { Id = collectionId };
var options = new RequestOptions { OfferType = offerType };
var result = await client.CreateDocumentCollectionAsync(database.SelfLink,
collectionDefinition, options);
var collection = result.Resource;
Console.WriteLine("Created new collection");
ViewCollection(collection);
}
private static void ViewCollection(DocumentCollection collection) {
Console.WriteLine("Collection ID: {0} ", collection.Id);
Console.WriteLine("Resource ID: {0} ", collection.ResourceId);
Console.WriteLine("Self Link: {0} ", collection.SelfLink);
Console.WriteLine("Documents Link: {0} ", collection.DocumentsLink);
Console.WriteLine("UDFs Link: {0} ", collection.UserDefinedFunctionsLink);
Console.WriteLine("StoredProcs Link: {0} ", collection.StoredProceduresLink);
Console.WriteLine("Triggers Link: {0} ", collection.TriggersLink);
Console.WriteLine("Timestamp: {0} ", collection.Timestamp);
}
private async static Task DeleteCollection(DocumentClient client,
string collectionId) {
Console.WriteLine();
Console.WriteLine("**** Delete Collection {0} in {1} ****", collectionId,
database.Id);
var query = new SqlQuerySpec {
QueryText = "SELECT * FROM c WHERE c.id = @id", Parameters = new
SqlParameterCollection {
new SqlParameter {
Name = "@id", Value = collectionId
}
}
};
DocumentCollection collection = client.CreateDocumentCollectionQuery
(database.SelfLink, query).AsEnumerable().First();
await client.DeleteDocumentCollectionAsync(collection.SelfLink);
Console.WriteLine("Deleted collection {0} from database {1}", collectionId,
database.Id);
}
}
}
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado.
**** Delete Collection TempCollection in myfirstdb ****
Deleted collection TempCollection from database myfirstdb
En este capítulo, trabajaremos con documentos reales en una colección. Puede crear documentos utilizando Azure Portal o .Net SDK.
Creación de documentos con Azure Portal
Echemos un vistazo a los siguientes pasos para agregar un documento a su colección.
Step 1 - Agregue una nueva colección de familias del nivel de precios S1 en myfirstdb.
Step 2 - Seleccione la colección Familias y haga clic en la opción Crear documento para abrir la hoja Nuevo documento.
Este es solo un editor de texto simple que le permite escribir cualquier JSON para un nuevo documento.
Step 3 - Como se trata de una entrada de datos sin procesar, entremos nuestro primer documento.
{
"id": "AndersenFamily",
"lastName": "Andersen",
"parents": [
{ "firstName": "Thomas", "relationship": "father" },
{ "firstName": "Mary Kay", "relationship": "mother" }
],
"children": [
{
"firstName": "Henriette Thaulow",
"gender": "female",
"grade": 5,
"pets": [ { "givenName": "Fluffy", "type": "Rabbit" } ]
}
],
"location": { "state": "WA", "county": "King", "city": "Seattle"},
"isRegistered": true
}
Cuando ingrese al documento anterior, verá la siguiente pantalla.
Tenga en cuenta que hemos proporcionado una identificación para el documento. El valor de id siempre es obligatorio y debe ser único en todos los demás documentos de la misma colección. Cuando lo omita, DocumentDB generará automáticamente uno para usted utilizando un GUID o un identificador único global.
La identificación es siempre una cadena y no puede ser un número, fecha, booleano u otro objeto, y no puede tener más de 255 caracteres.
También observe la estructura jerárquica del documento que tiene algunas propiedades de nivel superior como la identificación requerida, así como lastName y isRegistered, pero también tiene propiedades anidadas.
Por ejemplo, la propiedad principal se proporciona como una matriz JSON, como se indica con los corchetes. También tenemos otro arreglo para niños, aunque solo hay un niño en el arreglo en este ejemplo.
Step 4 - Haga clic en el botón 'Guardar' para guardar el documento y hemos creado nuestro primer documento.
Como puede ver, se aplicó un formato bonito a nuestro JSON, que divide cada propiedad en su propia línea con sangría con un espacio en blanco para transmitir el nivel de anidación de cada propiedad.
El portal incluye un Explorador de documentos, así que usémoslo ahora para recuperar el documento que acabamos de crear.
Step 5- Elija una base de datos y cualquier colección dentro de la base de datos para ver los documentos de esa colección. Actualmente solo tenemos una base de datos llamada myfirstdb con una colección llamada Familias, las cuales han sido preseleccionadas aquí en los menús desplegables.
De forma predeterminada, el Explorador de documentos muestra una lista sin filtrar de documentos dentro de la colección, pero también puede buscar cualquier documento específico por ID o varios documentos basados en una búsqueda con comodines de un ID parcial.
Hasta ahora solo tenemos un documento en nuestra colección, y vemos su ID en la siguiente pantalla, AndersonFamily.
Step 6 - Haga clic en la identificación para ver el documento.
Crear documentos con .NET SDK
Como sabe, los documentos son solo otro tipo de recurso y ya se ha familiarizado con cómo tratar los recursos utilizando el SDK.
La única gran diferencia entre los documentos y otros recursos es que, por supuesto, no tienen esquemas.
Por tanto, hay muchas opciones. Naturalmente, puede trabajar con gráficos de objetos JSON o incluso cadenas sin formato de texto JSON, pero también puede usar objetos dinámicos que le permitan enlazar propiedades en tiempo de ejecución sin definir una clase en tiempo de compilación.
También puede trabajar con objetos reales de C #, o Entidades como se les llama, que podrían ser sus clases de dominio empresarial.
Comencemos a crear documentos usando .Net SDK. Los siguientes son los pasos.
Step 1 - Cree una instancia de DocumentClient, luego consultaremos la base de datos myfirstdb y luego la colección MyCollection, que almacenamos en esta colección de variables privadas para que sea accesible en toda la clase.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'myfirstdb'").AsEnumerable().First();
collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
"SELECT * FROM c WHERE c.id = 'MyCollection'").AsEnumerable().First();
await CreateDocuments(client);
}
}
Step 2 - Crear algunos documentos en la tarea CreateDocuments.
private async static Task CreateDocuments(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Create Documents ****");
Console.WriteLine();
dynamic document1Definition = new {
name = "New Customer 1", address = new {
addressType = "Main Office",
addressLine1 = "123 Main Street",
location = new {
city = "Brooklyn", stateProvinceName = "New York"
}, postalCode = "11229", countryRegionName = "United States"
},
};
Document document1 = await CreateDocument(client, document1Definition);
Console.WriteLine("Created document {0} from dynamic object", document1.Id);
Console.WriteLine();
}
El primer documento se generará a partir de este objeto dinámico. Esto puede parecer JSON, pero por supuesto que no lo es. Este es código C # y estamos creando un objeto .NET real, pero no hay una definición de clase. En cambio, las propiedades se infieren de la forma en que se inicializa el objeto.
Tenga en cuenta que no hemos proporcionado una propiedad Id para este documento.
Ahora echemos un vistazo a CreateDocument. Parece el mismo patrón que vimos para crear bases de datos y colecciones.
private async static Task<Document> CreateDocument(DocumentClient client,
object documentObject) {
var result = await client.CreateDocumentAsync(collection.SelfLink, documentObject);
var document = result.Resource;
Console.WriteLine("Created new document: {0}\r\n{1}", document.Id, document);
return result;
}
Step 3- Esta vez llamamos CreateDocumentAsync especificando el SelfLink de la colección a la que queremos agregar el documento. Obtenemos una respuesta con una propiedad de recurso que, en este caso, representa el nuevo documento con sus propiedades generadas por el sistema.
El objeto Documento es una clase definida en el SDK que hereda del recurso y, por lo tanto, tiene todas las propiedades comunes del recurso, pero también incluye las propiedades dinámicas que definen el documento sin esquema en sí.
private async static Task CreateDocuments(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Create Documents ****");
Console.WriteLine();
dynamic document1Definition = new {
name = "New Customer 1", address = new {
addressType = "Main Office",
addressLine1 = "123 Main Street",
location = new {
city = "Brooklyn", stateProvinceName = "New York"
}, postalCode = "11229", countryRegionName = "United States"
},
};
Document document1 = await CreateDocument(client, document1Definition);
Console.WriteLine("Created document {0} from dynamic object", document1.Id);
Console.WriteLine();
}
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado.
**** Create Documents ****
Created new document: 34e9873a-94c8-4720-9146-d63fb7840fad {
"name": "New Customer 1",
"address": {
"addressType": "Main Office",
"addressLine1": "123 Main Street",
"location": {
"city": "Brooklyn", "stateProvinceName": "New York"
},
"postalCode": "11229", "countryRegionName": "United States"
},
"id": "34e9873a-94c8-4720-9146-d63fb7840fad",
"_rid": "Ic8LAMEUVgACAAAAAAAAAA==",
"_ts": 1449812756,
"_self": "dbs/Ic8LAA==/colls/Ic8LAMEUVgA=/docs/Ic8LAMEUVgACAAAAAAAAAA==/",
"_etag": "\"00001000-0000-0000-0000-566a63140000\"",
"_attachments": "attachments/"
}
Created document 34e9873a-94c8-4720-9146-d63fb7840fad from dynamic object
Como puede ver, no hemos proporcionado una identificación, sin embargo, DocumentDB generó esta para nosotros para el nuevo documento.
En DocumentDB, en realidad usamos SQL para consultar documentos, por lo que este capítulo trata sobre las consultas utilizando la sintaxis SQL especial en DocumentDB. Aunque si está desarrollando .NET, también hay un proveedor LINQ que se puede utilizar y que puede generar SQL apropiado a partir de una consulta LINQ.
Consultando documento usando Portal
Azure Portal tiene un Explorador de consultas que le permite ejecutar cualquier consulta SQL en su base de datos de DocumentDB.
Usaremos el Explorador de consultas para demostrar las diferentes capacidades y características del lenguaje de consulta, comenzando con la consulta más simple posible.
Step 1 - En la hoja de la base de datos, haga clic para abrir la hoja Explorador de consultas.
Recuerde que las consultas se ejecutan dentro del alcance de una colección, por lo que el Explorador de consultas le permite elegir la colección en este menú desplegable.
Step 2 - Seleccione la colección Familias que se creó anteriormente utilizando el portal.
El Explorador de consultas se abre con esta consulta simple SELECT * FROM c, que simplemente recupera todos los documentos de la colección.
Step 3- Ejecute esta consulta haciendo clic en el botón 'Ejecutar consulta'. Luego verá que el documento completo se recupera en la hoja Resultados.
Consultar documento con .Net SDK
Los siguientes son los pasos para ejecutar algunas consultas de documentos usando .Net SDK.
En este ejemplo, queremos consultar los documentos recién creados que acabamos de agregar.
Step 1 - Llame a CreateDocumentQuery, pasando la colección para ejecutar la consulta por su SelfLink y el texto de la consulta.
private async static Task QueryDocumentsWithPaging(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Query Documents (paged results) ****");
Console.WriteLine();
Console.WriteLine("Quering for all documents");
var sql = "SELECT * FROM c";
var query = client.CreateDocumentQuery(collection.SelfLink, sql).AsDocumentQuery();
while (query.HasMoreResults) {
var documents = await query.ExecuteNextAsync();
foreach (var document in documents) {
Console.WriteLine(" Id: {0}; Name: {1};", document.id, document.name);
}
}
Console.WriteLine();
}
Esta consulta también devuelve todos los documentos de la colección completa, pero no llamamos a .ToList en CreateDocumentQuery como antes, que emitiría tantas solicitudes como sea necesario para desplegar todos los resultados en una línea de código.
Step 2 - En su lugar, llame a AsDocumentQuery y este método devuelve un objeto de consulta con una propiedad HasMoreResults.
Step 3 - Si HasMoreResults es verdadero, entonces llame a ExecuteNextAsync para obtener el siguiente fragmento y luego volcar todo el contenido de ese fragmento.
Step 4- También puede consultar utilizando LINQ en lugar de SQL si lo prefiere. Aquí hemos definido una consulta LINQ en q, pero no se ejecutará hasta que ejecutemos .ToList en ella.
private static void QueryDocumentsWithLinq(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Query Documents (LINQ) ****");
Console.WriteLine();
Console.WriteLine("Quering for US customers (LINQ)");
var q =
from d in client.CreateDocumentQuery<Customer>(collection.DocumentsLink)
where d.Address.CountryRegionName == " United States"
select new {
Id = d.Id,
Name = d.Name,
City = d.Address.Location.City
};
var documents = q.ToList();
Console.WriteLine("Found {0} UK customers", documents.Count);
foreach (var document in documents) {
var d = document as dynamic;
Console.WriteLine(" Id: {0}; Name: {1}; City: {2}", d.Id, d.Name, d.City);
}
Console.WriteLine();
}
El SDK convertirá nuestra consulta LINQ en sintaxis SQL para DocumentDB, generando una cláusula SELECT y WHERE basada en nuestra sintaxis LINQ
Step 5 - Ahora llame a las consultas anteriores desde la tarea CreateDocumentClient.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'myfirstdb'").AsEnumerable().First();
collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
"SELECT * FROM c WHERE c.id = 'MyCollection'").AsEnumerable().First();
//await CreateDocuments(client);
await QueryDocumentsWithPaging(client);
QueryDocumentsWithLinq(client);
}
}
Cuando se ejecuta el código anterior, recibirá el siguiente resultado.
**** Query Documents (paged results) ****
Quering for all documents
Id: 7e9ad4fa-c432-4d1a-b120-58fd7113609f; Name: New Customer 1;
Id: 34e9873a-94c8-4720-9146-d63fb7840fad; Name: New Customer 1;
**** Query Documents (LINQ) ****
Quering for US customers (LINQ)
Found 2 UK customers
Id: 7e9ad4fa-c432-4d1a-b120-58fd7113609f; Name: New Customer 1; City: Brooklyn
Id: 34e9873a-94c8-4720-9146-d63fb7840fad; Name: New Customer 1; City: Brooklyn
En este capítulo, aprenderemos cómo actualizar los documentos. Con Azure Portal, puede actualizar fácilmente el documento abriéndolo en el Explorador de documentos y actualizándolo en el editor como un archivo de texto.
Haga clic en el botón "Guardar". Ahora, cuando necesite cambiar un documento usando .Net SDK, simplemente puede reemplazarlo. No es necesario eliminarlo y volver a crearlo, lo que además de ser tedioso, también cambiaría la identificación del recurso, lo que no querría hacer cuando solo está modificando un documento. Estos son los siguientes pasos para actualizar el documento usando .Net SDK.
Echemos un vistazo a la siguiente tarea ReplaceDocuments donde consultaremos documentos donde la propiedad isNew sea verdadera, pero no obtendremos ninguno porque no hay ninguno. Entonces, modifiquemos los documentos que agregamos anteriormente, aquellos cuyos nombres comienzan con Nuevo cliente.
Step 1 - Agregue la propiedad isNew a estos documentos y establezca su valor en verdadero.
private async static Task ReplaceDocuments(DocumentClient client) {
Console.WriteLine();
Console.WriteLine(">>> Replace Documents <<<");
Console.WriteLine();
Console.WriteLine("Quering for documents with 'isNew' flag");
var sql = "SELECT * FROM c WHERE c.isNew = true";
var documents = client.CreateDocumentQuery(collection.SelfLink, sql).ToList();
Console.WriteLine("Documents with 'isNew' flag: {0} ", documents.Count);
Console.WriteLine();
Console.WriteLine("Quering for documents to be updated");
sql = "SELECT * FROM c WHERE STARTSWITH(c.name, 'New Customer') = true";
documents = client.CreateDocumentQuery(collection.SelfLink, sql).ToList();
Console.WriteLine("Found {0} documents to be updated", documents.Count);
foreach (var document in documents) {
document.isNew = true;
var result = await client.ReplaceDocumentAsync(document._self, document);
var updatedDocument = result.Resource;
Console.WriteLine("Updated document 'isNew' flag: {0}", updatedDocument.isNew);
}
Console.WriteLine();
Console.WriteLine("Quering for documents with 'isNew' flag");
sql = "SELECT * FROM c WHERE c.isNew = true";
documents = client.CreateDocumentQuery(collection.SelfLink, sql).ToList();
Console.WriteLine("Documents with 'isNew' flag: {0}: ", documents.Count);
Console.WriteLine();
}
Step 2 - Obtener los documentos a actualizar utilizando la misma consulta INICIO CON Y eso nos da los documentos, que estamos recuperando aquí como objetos dinámicos.
Step 3 - Adjunte la propiedad isNew y configúrela como verdadera para cada documento.
Step 4 - Llame a ReplaceDocumentAsync, pasando el SelfLink del documento, junto con el documento actualizado.
Ahora solo para demostrar que esto funcionó, busque documentos donde isNew sea igual a verdadero. Llamemos a las consultas anteriores desde la tarea CreateDocumentClient.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'myfirstdb'").AsEnumerable().First();
collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
"SELECT * FROM c WHERE c.id = 'MyCollection'").AsEnumerable().First();
//await CreateDocuments(client);
//QueryDocumentsWithSql(client);
//await QueryDocumentsWithPaging(client);
//QueryDocumentsWithLinq(client);
await ReplaceDocuments(client);
}
}
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado.
**** Replace Documents ****
Quering for documents with 'isNew' flag
Documents with 'isNew' flag: 0
Quering for documents to be updated
Found 2 documents to be updated
Updated document ‘isNew’ flag: True
Updated document ‘isNew’ flag: True
Quering for documents with 'isNew' flag
Documents with 'isNew' flag: 2
En este capítulo, aprenderemos cómo eliminar un documento de su cuenta de DocumentDB. Con Azure Portal, puede eliminar fácilmente cualquier documento abriendo el documento en el Explorador de documentos y haciendo clic en la opción 'Eliminar'.
Mostrará el mensaje de confirmación. Ahora presione el botón Sí y verá que el documento ya no está disponible en su cuenta de DocumentDB.
Ahora, cuando desee eliminar un documento utilizando .Net SDK.
Step 1- Es el mismo patrón que hemos visto antes donde consultaremos primero para obtener los SelfLinks de cada nuevo documento. No usamos SELECT * aquí, lo que devolvería los documentos en su totalidad, lo que no necesitamos.
Step 2 - En su lugar, solo seleccionamos los SelfLinks en una lista y luego simplemente llamamos DeleteDocumentAsync para cada SelfLink, uno a la vez, para eliminar los documentos de la colección.
private async static Task DeleteDocuments(DocumentClient client) {
Console.WriteLine();
Console.WriteLine(">>> Delete Documents <<<");
Console.WriteLine();
Console.WriteLine("Quering for documents to be deleted");
var sql =
"SELECT VALUE c._self FROM c WHERE STARTSWITH(c.name, 'New Customer') = true";
var documentLinks =
client.CreateDocumentQuery<string>(collection.SelfLink, sql).ToList();
Console.WriteLine("Found {0} documents to be deleted", documentLinks.Count);
foreach (var documentLink in documentLinks) {
await client.DeleteDocumentAsync(documentLink);
}
Console.WriteLine("Deleted {0} new customer documents", documentLinks.Count);
Console.WriteLine();
}
Step 3 - Ahora llamemos a los DeleteDocuments anteriores desde la tarea CreateDocumentClient.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'myfirstdb'").AsEnumerable().First();
collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
"SELECT * FROM c WHERE c.id = 'MyCollection'").AsEnumerable().First();
await DeleteDocuments(client);
}
}
Cuando se ejecuta el código anterior, recibirá el siguiente resultado.
***** Delete Documents *****
Quering for documents to be deleted
Found 2 documents to be deleted
Deleted 2 new customer documents
Si bien las bases de datos sin esquema, como DocumentDB, facilitan la adopción de cambios en su modelo de datos, aún debe dedicar un tiempo a pensar en sus datos.
Tienes muchas opciones. Naturalmente, puede trabajar con gráficos de objetos JSON o incluso cadenas sin formato de texto JSON, pero también puede usar objetos dinámicos que le permitan enlazar propiedades en tiempo de ejecución sin definir una clase en tiempo de compilación.
También puede trabajar con objetos reales de C #, o Entidades como se les llama, que podrían ser sus clases de dominio empresarial.
Relaciones
Echemos un vistazo a la estructura jerárquica del documento. Tiene algunas propiedades de nivel superior como la identificación requerida, así como lastName e isRegistered, pero también tiene propiedades anidadas.
{
"id": "AndersenFamily",
"lastName": "Andersen",
"parents": [
{ "firstName": "Thomas", "relationship": "father" },
{ "firstName": "Mary Kay", "relationship": "mother" }
],
"children": [
{
"firstName": "Henriette Thaulow",
"gender": "female",
"grade": 5,
"pets": [ { "givenName": "Fluffy", "type": "Rabbit" } ]
}
],
"location": { "state": "WA", "county": "King", "city": "Seattle"},
"isRegistered": true
}
Por ejemplo, la propiedad principal se proporciona como una matriz JSON, como se indica con los corchetes.
También tenemos otro arreglo para niños, aunque solo hay un niño en el arreglo en este ejemplo. Así es como se modela el equivalente de relaciones de uno a muchos dentro de un documento.
Simplemente use matrices donde cada elemento de la matriz podría ser un valor simple u otro objeto complejo, incluso otra matriz.
Por lo tanto, una familia puede tener varios padres y varios hijos y, si observa los objetos secundarios, tienen la propiedad de una mascota que es en sí misma una matriz anidada para una relación uno a varios entre niños y mascotas.
Para la propiedad de ubicación, estamos combinando tres propiedades relacionadas, el estado, el condado y la ciudad en un objeto.
Incrustar un objeto de esta manera en lugar de incrustar una matriz de objetos es similar a tener una relación uno a uno entre dos filas en tablas separadas en una base de datos relacional.
Incrustar datos
Cuando comience a modelar datos en un almacén de documentos, como DocumentDB, intente tratar sus entidades como documentos autónomos representados en JSON. Cuando trabajamos con bases de datos relacionales, siempre normalizamos los datos.
Normalmente, la normalización de sus datos implica tomar una entidad, como un cliente, y dividirla en datos discretos, como detalles de contacto y direcciones.
Para leer a un cliente, con todos sus datos de contacto y direcciones, debe utilizar JOINS para agregar eficazmente sus datos en tiempo de ejecución.
Ahora echemos un vistazo a cómo modelaríamos los mismos datos como una entidad autónoma en una base de datos de documentos.
{
"id": "1",
"firstName": "Mark",
"lastName": "Upston",
"addresses": [
{
"line1": "232 Main Street",
"line2": "Unit 1",
"city": "Brooklyn",
"state": "NY",
"zip": 11229
}
],
"contactDetails": [
{"email": "[email protected]"},
{"phone": "+1 356 545-86455", "extension": 5555}
]
}
Como puede ver, hemos desnormalizado el registro del cliente donde toda la información del cliente está incrustada en un solo documento JSON.
En NoSQL tenemos un esquema gratuito, por lo que también puede agregar detalles de contacto y direcciones en diferentes formatos. En NoSQL, puede recuperar un registro de cliente de la base de datos en una sola operación de lectura. De manera similar, la actualización de un registro también es una operación de escritura única.
Los siguientes son los pasos para crear documentos usando .Net SDK.
Step 1- Crear una instancia de DocumentClient. Luego consultaremos la base de datos myfirstdb y también consultaremos la colección MyCollection, que almacenamos en esta colección de variables privadas para que sea accesible en toda la clase.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'myfirstdb'").AsEnumerable().First();
collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
"SELECT * FROM c WHERE c.id = 'MyCollection'").AsEnumerable().First();
await CreateDocuments(client);
}
}
Step 2 - Crear algunos documentos en la tarea CreateDocuments.
private async static Task CreateDocuments(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Create Documents ****");
Console.WriteLine();
dynamic document1Definition = new {
name = "New Customer 1", address = new {
addressType = "Main Office",
addressLine1 = "123 Main Street",
location = new {
city = "Brooklyn", stateProvinceName = "New York"
},
postalCode = "11229", countryRegionName = "United States"
},
};
Document document1 = await CreateDocument(client, document1Definition);
Console.WriteLine("Created document {0} from dynamic object", document1.Id);
Console.WriteLine();
}
El primer documento se generará a partir de este objeto dinámico. Esto puede parecer JSON, pero por supuesto que no lo es. Este es código C # y estamos creando un objeto .NET real, pero no hay una definición de clase. En cambio, las propiedades se infieren de la forma en que se inicializa el objeto. También puede observar que no hemos proporcionado una propiedad Id para este documento.
Step 3 - Ahora echemos un vistazo a CreateDocument y parece el mismo patrón que vimos para crear bases de datos y colecciones.
private async static Task<Document> CreateDocument(DocumentClient client,
object documentObject) {
var result = await client.CreateDocumentAsync(collection.SelfLink, documentObject);
var document = result.Resource;
Console.WriteLine("Created new document: {0}\r\n{1}", document.Id, document);
return result;
}
Step 4- Esta vez llamamos CreateDocumentAsync especificando el SelfLink de la colección a la que queremos agregar el documento. Obtenemos una respuesta con una propiedad de recurso que, en este caso, representa el nuevo documento con sus propiedades generadas por el sistema.
En la siguiente tarea CreateDocuments, hemos creado tres documentos.
En el primer documento, el objeto Documento es una clase definida en el SDK que hereda del recurso y, por lo tanto, tiene todas las propiedades comunes del recurso, pero también incluye las propiedades dinámicas que definen el documento sin esquema en sí.
private async static Task CreateDocuments(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Create Documents ****");
Console.WriteLine();
dynamic document1Definition = new {
name = "New Customer 1", address = new {
addressType = "Main Office",
addressLine1 = "123 Main Street",
location = new {
city = "Brooklyn", stateProvinceName = "New York"
},
postalCode = "11229",
countryRegionName = "United States"
},
};
Document document1 = await CreateDocument(client, document1Definition);
Console.WriteLine("Created document {0} from dynamic object", document1.Id);
Console.WriteLine();
var document2Definition = @" {
""name"": ""New Customer 2"",
""address"": {
""addressType"": ""Main Office"",
""addressLine1"": ""123 Main Street"",
""location"": {
""city"": ""Brooklyn"", ""stateProvinceName"": ""New York""
},
""postalCode"": ""11229"",
""countryRegionName"": ""United States""
}
}";
Document document2 = await CreateDocument(client, document2Definition);
Console.WriteLine("Created document {0} from JSON string", document2.Id);
Console.WriteLine();
var document3Definition = new Customer {
Name = "New Customer 3",
Address = new Address {
AddressType = "Main Office",
AddressLine1 = "123 Main Street",
Location = new Location {
City = "Brooklyn", StateProvinceName = "New York"
},
PostalCode = "11229",
CountryRegionName = "United States"
},
};
Document document3 = await CreateDocument(client, document3Definition);
Console.WriteLine("Created document {0} from typed object", document3.Id);
Console.WriteLine();
}
Este segundo documento solo funciona con una cadena JSON sin procesar. Ahora entramos en una sobrecarga para CreateDocument que usa JavaScriptSerializer para deserializar la cadena en un objeto, que luego pasa al mismo método CreateDocument que usamos para crear el primer documento.
En el tercer documento, hemos utilizado el objeto C # Customer que se define en nuestra aplicación.
Echemos un vistazo a este cliente, tiene una propiedad de Id y dirección donde la dirección es un objeto anidado con sus propias propiedades, incluida la ubicación, que es otro objeto anidado.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DocumentDBDemo {
public class Customer {
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
// Must be nullable, unless generating unique values for new customers on client
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "address")]
public Address Address { get; set; }
}
public class Address {
[JsonProperty(PropertyName = "addressType")]
public string AddressType { get; set; }
[JsonProperty(PropertyName = "addressLine1")]
public string AddressLine1 { get; set; }
[JsonProperty(PropertyName = "location")]
public Location Location { get; set; }
[JsonProperty(PropertyName = "postalCode")]
public string PostalCode { get; set; }
[JsonProperty(PropertyName = "countryRegionName")]
public string CountryRegionName { get; set; }
}
public class Location {
[JsonProperty(PropertyName = "city")]
public string City { get; set; }
[JsonProperty(PropertyName = "stateProvinceName")]
public string StateProvinceName { get; set; }
}
}
También tenemos atributos de propiedad JSON en su lugar porque queremos mantener las convenciones adecuadas en ambos lados de la cerca.
Así que simplemente creo mi objeto New Customer junto con sus objetos secundarios anidados y llamo a CreateDocument una vez más. Aunque nuestro objeto de cliente tiene una propiedad Id, no le proporcionamos un valor y, por lo tanto, DocumentDB generó uno basado en el GUID, al igual que lo hizo para los dos documentos anteriores.
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado.
**** Create Documents ****
Created new document: 575882f0-236c-4c3d-81b9-d27780206b2c
{
"name": "New Customer 1",
"address": {
"addressType": "Main Office",
"addressLine1": "123 Main Street",
"location": {
"city": "Brooklyn",
"stateProvinceName": "New York"
},
"postalCode": "11229",
"countryRegionName": "United States"
},
"id": "575882f0-236c-4c3d-81b9-d27780206b2c",
"_rid": "kV5oANVXnwDGPgAAAAAAAA==",
"_ts": 1450037545,
"_self": "dbs/kV5oAA==/colls/kV5oANVXnwA=/docs/kV5oANVXnwDGPgAAAAAAAA==/",
"_etag": "\"00006fce-0000-0000-0000-566dd1290000\"",
"_attachments": "attachments/"
}
Created document 575882f0-236c-4c3d-81b9-d27780206b2c from dynamic object
Created new document: 8d7ad239-2148-4fab-901b-17a85d331056
{
"name": "New Customer 2",
"address": {
"addressType": "Main Office",
"addressLine1": "123 Main Street",
"location": {
"city": "Brooklyn",
"stateProvinceName": "New York"
},
"postalCode": "11229",
"countryRegionName": "United States"
},
"id": "8d7ad239-2148-4fab-901b-17a85d331056",
"_rid": "kV5oANVXnwDHPgAAAAAAAA==",
"_ts": 1450037545,
"_self": "dbs/kV5oAA==/colls/kV5oANVXnwA=/docs/kV5oANVXnwDHPgAAAAAAAA==/",
"_etag": "\"000070ce-0000-0000-0000-566dd1290000\"",
"_attachments": "attachments/"
}
Created document 8d7ad239-2148-4fab-901b-17a85d331056 from JSON string
Created new document: 49f399a8-80c9-4844-ac28-cd1dee689968
{
"id": "49f399a8-80c9-4844-ac28-cd1dee689968",
"name": "New Customer 3",
"address": {
"addressType": "Main Office",
"addressLine1": "123 Main Street",
"location": {
"city": "Brooklyn",
"stateProvinceName": "New York"
},
"postalCode": "11229",
"countryRegionName": "United States"
},
"_rid": "kV5oANVXnwDIPgAAAAAAAA==",
"_ts": 1450037546,
"_self": "dbs/kV5oAA==/colls/kV5oANVXnwA=/docs/kV5oANVXnwDIPgAAAAAAAA==/",
"_etag": "\"000071ce-0000-0000-0000-566dd12a0000\"",
"_attachments": "attachments/"
}
Created document 49f399a8-80c9-4844-ac28-cd1dee689968 from typed object
JSON o JavaScript Object Notation es un estándar abierto ligero basado en texto diseñado para el intercambio de datos legibles por humanos y también fácil de analizar y generar para las máquinas. JSON está en el corazón de DocumentDB. Transmitimos JSON a través del cable, almacenamos JSON como JSON e indexamos el árbol JSON permitiendo consultas en el documento JSON completo.
El formato JSON admite los siguientes tipos de datos:
S.No. | Tipo y descripción |
---|---|
1 | Number Formato de punto flotante de doble precisión en JavaScript |
2 | String Unicode de comillas dobles con escape de barra invertida |
3 | Boolean Verdadero o falso |
4 | Array Una secuencia ordenada de valores |
5 | Value Puede ser una cadena, un número, verdadero o falso, nulo, etc. |
6 | Object Una colección desordenada de pares clave: valor |
7 | Whitespace Se puede usar entre cualquier par de tokens. |
8 | Null Vacío |
Echemos un vistazo a un ejemplo simple del tipo DateTime. Agregue la fecha de nacimiento a la clase de cliente.
public class Customer {
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
// Must be nullable, unless generating unique values for new customers on client
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
[JsonProperty(PropertyName = "address")]
public Address Address { get; set; }
[JsonProperty(PropertyName = "birthDate")]
public DateTime BirthDate { get; set; }
}
Podemos almacenar, recuperar y consultar usando DateTime como se muestra en el siguiente código.
private async static Task CreateDocuments(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Create Documents ****");
Console.WriteLine();
var document3Definition = new Customer {
Id = "1001",
Name = "Luke Andrew",
Address = new Address {
AddressType = "Main Office",
AddressLine1 = "123 Main Street",
Location = new Location {
City = "Brooklyn",
StateProvinceName = "New York"
},
PostalCode = "11229",
CountryRegionName = "United States"
},
BirthDate = DateTime.Parse(DateTime.Today.ToString()),
};
Document document3 = await CreateDocument(client, document3Definition);
Console.WriteLine("Created document {0} from typed object", document3.Id);
Console.WriteLine();
}
Cuando se compile y ejecute el código anterior, y se cree el documento, verá que ahora se agrega la fecha de nacimiento.
**** Create Documents ****
Created new document: 1001
{
"id": "1001",
"name": "Luke Andrew",
"address": {
"addressType": "Main Office",
"addressLine1": "123 Main Street",
"location": {
"city": "Brooklyn",
"stateProvinceName": "New York"
},
"postalCode": "11229",
"countryRegionName": "United States"
},
"birthDate": "2015-12-14T00:00:00",
"_rid": "Ic8LAMEUVgAKAAAAAAAAAA==",
"_ts": 1450113676,
"_self": "dbs/Ic8LAA==/colls/Ic8LAMEUVgA=/docs/Ic8LAMEUVgAKAAAAAAAAAA==/",
"_etag": "\"00002d00-0000-0000-0000-566efa8c0000\"",
"_attachments": "attachments/"
}
Created document 1001 from typed object
Microsoft ha agregado recientemente una serie de mejoras sobre cómo puede consultar Azure DocumentDB, como la palabra clave TOP en la gramática SQL, que hizo que las consultas se ejecutaran más rápido y consumieran menos recursos, aumentó los límites para los operadores de consultas y agregó soporte para operadores LINQ adicionales en el .NET SDK.
Echemos un vistazo a un ejemplo simple en el que recuperaremos solo los dos primeros registros. Si tiene varios registros y desea recuperar solo algunos de ellos, puede usar la palabra clave Top. En este ejemplo, tenemos muchos registros de terremotos.
Ahora queremos mostrar solo los dos primeros registros
Step 1 - Vaya al explorador de consultas y ejecute esta consulta.
SELECT * FROM c
WHERE c.magnitude > 2.5
Verá que ha recuperado cuatro registros porque aún no hemos especificado la palabra clave TOP.
Step 2- Ahora use la palabra clave TOP con la misma consulta. Aquí hemos especificado la palabra clave TOP y '2' significa que solo queremos dos registros.
SELECT TOP 2 * FROM c
WHERE c.magnitude > 2.5
Step 3 - Ahora ejecute esta consulta y verá que solo se recuperan dos registros.
De manera similar, puede usar la palabra clave TOP en el código usando .Net SDK. A continuación se muestra la implementación.
private async static Task QueryDocumentsWithPaging(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Query Documents (paged results) ****");
Console.WriteLine();
Console.WriteLine("Quering for all documents");
var sql = "SELECT TOP 3 * FROM c";
var query = client
.CreateDocumentQuery(collection.SelfLink, sql)
.AsDocumentQuery();
while (query.HasMoreResults) {
var documents = await query.ExecuteNextAsync();
foreach (var document in documents) {
Console.WriteLine(" PublicId: {0}; Magnitude: {1};", document.publicid,
document.magnitude);
}
}
Console.WriteLine();
}
A continuación se muestra la tarea CreateDocumentClient en la que se crean instancias de DocumentClient y la base de datos de terremotos.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'earthquake'").AsEnumerable().First();
collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
"SELECT * FROM c WHERE c.id = 'earthquakedata'").AsEnumerable().First();
await QueryDocumentsWithPaging(client);
}
}
Cuando se compila y ejecuta el código anterior, verá que solo se recuperan tres registros.
**** Query Documents (paged results) ****
Quering for all documents
PublicId: 2015p947400; Magnitude: 2.515176918;
PublicId: 2015p947373; Magnitude: 1.506774108;
PublicId: 2015p947329; Magnitude: 1.593394461;
Microsoft Azure DocumentDB admite la consulta de documentos mediante SQL sobre documentos JSON. Puede ordenar los documentos de la colección por números y cadenas utilizando una cláusula ORDER BY en su consulta. La cláusula puede incluir un argumento opcional ASC / DESC para especificar el orden en el que se deben recuperar los resultados.
Echemos un vistazo al siguiente ejemplo en el que tenemos un documento JSON.
{
"id": "Food Menu",
"description": "Grapes, red or green (European type, such as Thompson seedless), raw",
"tags": [
{
"name": "grapes"
},
{
"name": "red or green (european type"
},
{
"name": "such as thompson seedless)"
},
{
"name": "raw"
}
],
"foodGroup": "Fruits and Fruit Juices",
"servings": [
{
"amount": 1,
"description": "cup",
"weightInGrams": 151
},
{
"amount": 10,
"description": "grapes",
"weightInGrams": 49
},
{
"amount": 1,
"description": "NLEA serving",
"weightInGrams": 126
}
]
}
A continuación se muestra la consulta SQL para ordenar el resultado en orden descendente.
SELECT f.description, f.foodGroup,
f.servings[2].description AS servingDescription,
f.servings[2].weightInGrams AS servingWeight
FROM f
ORDER BY f.servings[2].weightInGrams DESC
Cuando se ejecuta la consulta anterior, recibirá el siguiente resultado.
[
{
"description": "Grapes, red or green (European type, such as Thompson
seedless), raw",
"foodGroup": "Fruits and Fruit Juices",
"servingDescription": "NLEA serving",
"servingWeight": 126
}
]
De forma predeterminada, DocumentDB indexa automáticamente todas las propiedades de un documento tan pronto como el documento se agrega a la base de datos. Sin embargo, puede tomar el control y ajustar su propia política de indexación que reduce la sobrecarga de almacenamiento y procesamiento cuando hay documentos o propiedades específicos que nunca necesitan indexarse.
La política de indexación predeterminada que le dice a DocumentDB que indexe cada propiedad automáticamente es adecuada para muchos escenarios comunes. Pero también puede implementar una política personalizada que ejerza un control preciso sobre exactamente qué se indexa y qué no, y otras funciones con respecto a la indexación.
DocumentDB admite los siguientes tipos de indexación:
- Hash
- Range
Picadillo
El índice hash permite una consulta eficiente para la igualdad, es decir, al buscar documentos donde una propiedad dada es igual a un valor exacto, en lugar de coincidir en un rango de valores como menor que, mayor que o entre.
Puede realizar consultas de rango con un índice hash, pero DocumentDB no podrá usar el índice hash para encontrar documentos coincidentes y, en su lugar, deberá escanear secuencialmente cada documento para determinar si debe ser seleccionado por la consulta de rango.
No podrá ordenar sus documentos con una cláusula ORDER BY en una propiedad que solo tenga un índice hash.
Rango
Índice de rango definido para la propiedad, DocumentDB permite consultar de manera eficiente documentos contra un rango de valores. También le permite ordenar los resultados de la consulta en esa propiedad, usando ORDER BY.
DocumentDB le permite definir tanto un hash como un índice de rango en cualquiera o todas las propiedades, lo que permite consultas eficientes de igualdad y rango, así como ORDER BY.
Política de indexación
Cada colección tiene una política de indexación que dicta qué tipos de índices se utilizan para números y cadenas en cada propiedad de cada documento.
También puede controlar si los documentos se indexan automáticamente a medida que se agregan a la colección.
La indexación automática está habilitada de forma predeterminada, pero puede anular ese comportamiento al agregar un documento, indicando a DocumentDB que no indexe ese documento en particular.
Puede deshabilitar la indexación automática para que, de forma predeterminada, los documentos no se indexen cuando se agreguen a la colección. De manera similar, puede anular esto a nivel de documento e indicar a DocumentDB que indexe un documento en particular cuando lo agregue a la colección. Esto se conoce como indexación manual.
Incluir / excluir indexación
Una política de indexación también puede definir qué ruta o rutas deben incluirse o excluirse del índice. Esto es útil si sabe que hay ciertas partes de un documento que nunca consulta y ciertas partes que sí.
En estos casos, puede reducir la sobrecarga de indexación diciéndole a DocumentDB que indexe solo aquellas partes particulares de cada documento agregado a la colección.
Indexación automática
Echemos un vistazo a un ejemplo sencillo de indexación automática.
Step 1 - Primero creamos una colección llamada autoindexación y sin proporcionar explícitamente una política, esta colección usa la política de indexación predeterminada, lo que significa que la indexación automática está habilitada en esta colección.
Aquí estamos usando enrutamiento basado en ID para el autoenlace de la base de datos, por lo que no necesitamos saber su ID de recurso o consultarlo antes de crear la colección. Podemos simplemente usar el ID de la base de datos, que es mydb.
Step 2 - Ahora creemos dos documentos, ambos con el apellido Upston.
private async static Task AutomaticIndexing(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Override Automatic Indexing ****");
// Create collection with automatic indexing
var collectionDefinition = new DocumentCollection {
Id = "autoindexing"
};
var collection = await client.CreateDocumentCollectionAsync("dbs/mydb",
collectionDefinition);
// Add a document (indexed)
dynamic indexedDocumentDefinition = new {
id = "MARK",
firstName = "Mark",
lastName = "Upston",
addressLine = "123 Main Street",
city = "Brooklyn",
state = "New York",
zip = "11229",
};
Document indexedDocument = await client
.CreateDocumentAsync("dbs/mydb/colls/autoindexing", indexedDocumentDefinition);
// Add another document (request no indexing)
dynamic unindexedDocumentDefinition = new {
id = "JANE",
firstName = "Jane",
lastName = "Upston",
addressLine = "123 Main Street",
city = "Brooklyn",
state = "New York",
zip = "11229",
};
Document unindexedDocument = await client
.CreateDocumentAsync("dbs/mydb/colls/autoindexing", unindexedDocumentDefinition,
new RequestOptions { IndexingDirective = IndexingDirective.Exclude });
//Unindexed document won't get returned when querying on non-ID (or selflink) property
var doeDocs = client.CreateDocumentQuery("dbs/mydb/colls/autoindexing", "SELECT *
FROM c WHERE c.lastName = 'Doe'").ToList();
Console.WriteLine("Documents WHERE lastName = 'Doe': {0}", doeDocs.Count);
// Unindexed document will get returned when using no WHERE clause
var allDocs = client.CreateDocumentQuery("dbs/mydb/colls/autoindexing",
"SELECT * FROM c").ToList();
Console.WriteLine("All documents: {0}", allDocs.Count);
// Unindexed document will get returned when querying by ID (or self-link) property
Document janeDoc = client.CreateDocumentQuery("dbs/mydb/colls/autoindexing",
"SELECT * FROM c WHERE c.id = 'JANE'").AsEnumerable().FirstOrDefault();
Console.WriteLine("Unindexed document self-link: {0}", janeDoc.SelfLink);
// Delete the collection
await client.DeleteDocumentCollectionAsync("dbs/mydb/colls/autoindexing");
}
Este primero, para Mark Upston, se agrega a la colección y luego se indexa inmediatamente de forma automática según la política de indexación predeterminada.
Pero cuando se agrega el segundo documento para Mark Upston, pasamos las opciones de solicitud con IndexingDirective.Exclude, que indica explícitamente a DocumentDB que no indexe este documento, a pesar de la política de indexación de la colección.
Tenemos diferentes tipos de consultas tanto para los documentos al final.
Step 3 - Llamemos a la tarea AutomaticIndexing desde CreateDocumentClient.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
await AutomaticIndexing(client);
}
}
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado.
**** Override Automatic Indexing ****
Documents WHERE lastName = 'Upston': 1
All documents: 2
Unindexed document self-link: dbs/kV5oAA==/colls/kV5oAOEkfQA=/docs/kV5oAOEkfQACA
AAAAAAAAA==/
Como puede ver, tenemos dos de esos documentos, pero la consulta devuelve solo el de Mark porque el de Mark no está indexado. Si consultamos de nuevo, sin una cláusula WHERE para recuperar todos los documentos de la colección, obtenemos un conjunto de resultados con ambos documentos y esto se debe a que los documentos no indexados siempre son devueltos por consultas que no tienen cláusula WHERE.
También podemos recuperar documentos no indexados por su ID o autoenlace. Entonces, cuando consultamos el documento de Mark por su ID, MARK, vemos que DocumentDB devuelve el documento aunque no esté indexado en la colección.
Indexación manual
Echemos un vistazo a un ejemplo simple de indexación manual anulando la indexación automática.
Step 1- Primero crearemos una colección llamada indexación manual y anularemos la política predeterminada desactivando explícitamente la indexación automática. Esto significa que, a menos que solicitemos lo contrario, los nuevos documentos agregados a esta colección no serán indexados.
private async static Task ManualIndexing(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Manual Indexing ****");
// Create collection with manual indexing
var collectionDefinition = new DocumentCollection {
Id = "manualindexing",
IndexingPolicy = new IndexingPolicy {
Automatic = false,
},
};
var collection = await client.CreateDocumentCollectionAsync("dbs/mydb",
collectionDefinition);
// Add a document (unindexed)
dynamic unindexedDocumentDefinition = new {
id = "MARK",
firstName = "Mark",
lastName = "Doe",
addressLine = "123 Main Street",
city = "Brooklyn",
state = "New York",
zip = "11229",
};
Document unindexedDocument = await client
.CreateDocumentAsync("dbs/mydb/colls/manualindexing", unindexedDocumentDefinition);
// Add another document (request indexing)
dynamic indexedDocumentDefinition = new {
id = "JANE",
firstName = "Jane",
lastName = "Doe",
addressLine = "123 Main Street",
city = "Brooklyn",
state = "New York",
zip = "11229",
};
Document indexedDocument = await client.CreateDocumentAsync
("dbs/mydb/colls/manualindexing", indexedDocumentDefinition, new RequestOptions {
IndexingDirective = IndexingDirective.Include });
//Unindexed document won't get returned when querying on non-ID (or selflink) property
var doeDocs = client.CreateDocumentQuery("dbs/mydb/colls/manualindexing",
"SELECT * FROM c WHERE c.lastName = 'Doe'").ToList();
Console.WriteLine("Documents WHERE lastName = 'Doe': {0}", doeDocs.Count);
// Unindexed document will get returned when using no WHERE clause
var allDocs = client.CreateDocumentQuery("dbs/mydb/colls/manualindexing",
"SELECT * FROM c").ToList();
Console.WriteLine("All documents: {0}", allDocs.Count);
// Unindexed document will get returned when querying by ID (or self-link) property
Document markDoc = client
.CreateDocumentQuery("dbs/mydb/colls/manualindexing",
"SELECT * FROM c WHERE c.id = 'MARK'")
.AsEnumerable().FirstOrDefault();
Console.WriteLine("Unindexed document self-link: {0}", markDoc.SelfLink);
await client.DeleteDocumentCollectionAsync("dbs/mydb/colls/manualindexing");
}
Step 2- Ahora crearemos nuevamente los mismos dos documentos que antes. No proporcionaremos ninguna opción de solicitud especial para el documento de Mark esta vez, debido a la política de indexación de la colección, este documento no se indexará.
Step 3 - Ahora, cuando agregamos el segundo documento para Mark, usamos RequestOptions con IndexingDirective.Include para decirle a DocumentDB que debe indexar este documento, lo que anula la política de indexación de la colección que dice que no debería.
Tenemos diferentes tipos de consultas tanto para los documentos al final.
Step 4 - Llamemos a la tarea ManualIndexing desde CreateDocumentClient.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
await ManualIndexing(client);
}
}
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado.
**** Manual Indexing ****
Documents WHERE lastName = 'Upston': 1
All documents: 2
Unindexed document self-link: dbs/kV5oAA==/colls/kV5oANHJPgE=/docs/kV5oANHJPgEBA
AAAAAAAAA==/
Nuevamente, la consulta devuelve solo uno de los dos documentos, pero esta vez, devuelve Jane Doe, que solicitamos explícitamente que se indexe. Pero nuevamente, como antes, al consultar sin una cláusula WHERE se recuperan todos los documentos de la colección, incluido el documento no indexado de Mark. También podemos consultar el documento no indexado por su ID, que DocumentDB devuelve aunque no esté indexado.
Microsoft agregó geospatial support, que le permite almacenar datos de ubicación en sus documentos y realizar cálculos espaciales de distancia e intersecciones entre puntos y polígonos.
Los datos espaciales describen la posición y la forma de los objetos en el espacio.
Normalmente, se puede utilizar para representar la ubicación de una persona, un lugar de interés o los límites de una ciudad o un lago.
Los casos de uso comunes a menudo involucran consultas de proximidad. Por ejemplo, "buscar todas las universidades cercanas a mi ubicación actual".
UN Pointindica una única posición en el espacio que representa la ubicación exacta, por ejemplo, la dirección de la calle de una universidad en particular. Un punto se representa en DocumentDB utilizando su par de coordenadas (longitud y latitud). A continuación se muestra un ejemplo de punto JSON.
{
"type":"Point",
"coordinates":[ 28.3, -10.7 ]
}
Echemos un vistazo a un ejemplo sencillo que contiene la ubicación de una universidad.
{
"id":"case-university",
"name":"CASE: Center For Advanced Studies In Engineering",
"city":"Islamabad",
"location": {
"type":"Point",
"coordinates":[ 33.7194136, -73.0964862 ]
}
}
Para recuperar el nombre de la universidad según la ubicación, puede utilizar la siguiente consulta.
SELECT c.name FROM c
WHERE c.id = "case-university" AND ST_ISVALID({
"type":"Point",
"coordinates":[ 33.7194136, -73.0964862 ]})
Cuando se ejecuta la consulta anterior, recibirá el siguiente resultado.
[
{
"name": "CASE: Center For Advanced Studies In Engineering"
}
]
Crear documento con datos geoespaciales en .NET
Puede crear un documento con datos geoespaciales, echemos un vistazo a un ejemplo sencillo en el que se crea un documento universitario.
private async static Task CreateDocuments(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Create Documents ****");
Console.WriteLine();
var uniDocument = new UniversityProfile {
Id = "nust",
Name = "National University of Sciences and Technology",
City = "Islamabad",
Loc = new Point(33.6455715, 72.9903447)
};
Document document = await CreateDocument(client, uniDocument);
Console.WriteLine("Created document {0} from typed object", document.Id);
Console.WriteLine();
}
A continuación se muestra la implementación para la clase UniversityProfile.
public class UniversityProfile {
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("city")]
public string City { get; set; }
[JsonProperty("location")]
public Point Loc { get; set; }
}
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado.
**** Create Documents ****
Created new document: nust
{
"id": "nust",
"name": "National University of Sciences and Technology",
"city": "Islamabad",
"location": {
"type": "Point",
"coordinates": [
33.6455715,
72.9903447
]
},
"_rid": "Ic8LAMEUVgANAAAAAAAAAA==",
"_ts": 1450200910,
"_self": "dbs/Ic8LAA==/colls/Ic8LAMEUVgA=/docs/Ic8LAMEUVgANAAAAAAAAAA==/",
"_etag": "\"00004100-0000-0000-0000-56704f4e0000\"",
"_attachments": "attachments/"
}
Created document nust from typed object
Cuando su base de datos comience a crecer más allá de los 10 GB, puede escalar horizontalmente simplemente creando nuevas colecciones y luego distribuyendo o particionando sus datos en más y más colecciones.
Tarde o temprano, una sola colección, que tiene una capacidad de 10GB, no será suficiente para contener su base de datos. Ahora, 10GB puede no parecer un número muy grande, pero recuerde que estamos almacenando documentos JSON, que son solo texto sin formato y puede colocar muchos documentos de texto sin formato en 10GB, incluso si considera la sobrecarga de almacenamiento para los índices.
El almacenamiento no es la única preocupación cuando se trata de escalabilidad. El rendimiento máximo disponible en una colección es de dos mil quinientas unidades de solicitud por segundo que obtiene con una colección S3. Por lo tanto, si necesita un mayor rendimiento, también deberá escalar horizontalmente mediante la partición con varias colecciones. La partición escalable también se llamahorizontal partitioning.
Hay muchos enfoques que se pueden usar para particionar datos con Azure DocumentDB. Las siguientes son las estrategias más comunes:
- Partición de desbordamiento
- Partición de rango
- Partición de búsqueda
- Particionamiento hash
Partición de desbordamiento
La partición indirecta es la estrategia más simple porque no hay una clave de partición. A menudo, es una buena opción para empezar cuando no está seguro de muchas cosas. Es posible que no sepa si alguna vez necesitará escalar más allá de una sola colección o cuántas colecciones puede necesitar agregar o qué tan rápido puede necesitar agregarlas.
La partición de desbordamiento comienza con una sola colección y no hay una clave de partición.
La colección comienza a crecer y luego crece un poco más, y luego un poco más, hasta que comienzas a acercarte al límite de 10GB.
Cuando alcanza el 90 por ciento de su capacidad, pasa a una nueva colección y comienza a usarla para nuevos documentos.
Una vez que su base de datos se amplíe a una mayor cantidad de colecciones, probablemente querrá cambiar a una estrategia basada en una clave de partición.
Cuando haga eso, deberá reequilibrar sus datos moviendo documentos a diferentes colecciones según la estrategia a la que esté migrando.
Partición de rango
Una de las estrategias más comunes es la división de rangos. Con este enfoque, usted determina el rango de valores en el que podría caer la clave de partición de un documento y dirige el documento a una colección correspondiente a ese rango.
Las fechas se usan muy típicamente con esta estrategia en la que crea una colección para contener documentos que se encuentran dentro del rango de fechas definido. Cuando define rangos que son lo suficientemente pequeños, donde está seguro de que ninguna colección superará su límite de 10 GB. Por ejemplo, puede haber un escenario en el que una sola colección pueda manejar documentos de manera razonable durante todo un mes.
También puede darse el caso de que la mayoría de los usuarios busquen datos actuales, que serían datos de este mes o quizás del mes pasado, pero los usuarios rara vez buscan datos mucho más antiguos. Así que comienza en junio con una colección S3, que es la colección más cara que puede comprar y ofrece el mejor rendimiento que puede obtener.
En julio, compra otra colección S3 para almacenar los datos de julio y también escala los datos de junio a una colección S2 menos costosa. Luego, en agosto, obtienes otra colección S3 y escalas julio a un S2 y junio hasta un S1. Continúa, mes tras mes, donde siempre mantiene los datos actuales disponibles para un alto rendimiento y los datos más antiguos se mantienen disponibles a un rendimiento más bajo.
Siempre que la consulta proporcione una clave de partición, solo se consultará la colección que debe consultarse y no todas las colecciones de la base de datos como sucede con la partición de desbordamiento.
Partición de búsqueda
Con el particionamiento de búsqueda, puede definir un mapa de partición que enrute documentos a colecciones específicas según su clave de partición. Por ejemplo, puede dividir por región.
Almacene todos los documentos estadounidenses en una colección, todos los documentos europeos en otra colección y todos los documentos de cualquier otra región en una tercera colección.
Utilice este mapa de particiones y un solucionador de particiones de búsqueda puede averiguar en qué colección crear un documento y en qué colecciones consultar, según la clave de partición, que es la propiedad de la región contenida en cada documento.
Particionamiento hash
En el particionamiento hash, las particiones se asignan según el valor de una función hash, lo que le permite distribuir de manera uniforme las solicitudes y los datos en varias particiones.
Esto se usa comúnmente para particionar datos producidos o consumidos de una gran cantidad de clientes distintos y es útil para almacenar perfiles de usuario, elementos de catálogo, etc.
Echemos un vistazo a un ejemplo simple de partición de rango utilizando RangePartitionResolver suministrado por .NET SDK.
Step 1- Cree un nuevo DocumentClient y crearemos dos colecciones en la tarea CreateCollections. Uno contendrá documentos para los usuarios que tienen ID de usuario que comienzan con A a M y el otro para ID de usuario N a Z.
private static async Task CreateCollections(DocumentClient client) {
await client.CreateDocumentCollectionAsync(“dbs/myfirstdb”, new DocumentCollection {
Id = “CollectionAM” });
await client.CreateDocumentCollectionAsync(“dbs/myfirstdb”, new DocumentCollection {
Id = “CollectionNZ” });
}
Step 2 - Registrar el resolutor de rango para la base de datos.
Step 3- Cree un nuevo RangePartitionResolver <string>, que es el tipo de datos de nuestra clave de partición. El constructor toma dos parámetros, el nombre de propiedad de la clave de partición y un diccionario que es el mapa de particiones o mapa de partición, que es solo una lista de los rangos y las colecciones correspondientes que estamos predefiniendo para el resolutor.
private static void RegisterRangeResolver(DocumentClient client) {
//Note: \uffff is the largest UTF8 value, so M\ufff includes all strings that start with M.
var resolver = new RangePartitionResolver<string>(
"userId", new Dictionary<Range<string>, string>() {
{ new Range<string>("A", "M\uffff"), "dbs/myfirstdb/colls/CollectionAM" },
{ new Range<string>("N", "Z\uffff"), "dbs/myfirstdb/colls/CollectionNZ" },
});
client.PartitionResolvers["dbs/myfirstdb"] = resolver;
}
Es necesario codificar aquí el valor UTF-8 más grande posible. De lo contrario, el primer rango no coincidiría con ninguna M excepto la única M, y lo mismo ocurre con Z en el segundo rango. Por lo tanto, puede pensar en este valor codificado aquí como un comodín para hacer coincidir la clave de partición.
Step 4- Después de crear el resolutor, regístrelo para la base de datos con el DocumentClient actual. Para hacer eso, simplemente asígnelo a la propiedad de diccionario de PartitionResolver.
Crearemos y consultaremos documentos contra la base de datos, no una colección como lo hace normalmente, el solucionador usará este mapa para enrutar las solicitudes a las colecciones apropiadas.
Ahora creemos algunos documentos. Primero crearemos uno para userId Kirk y luego uno para Spock.
private static async Task CreateDocumentsAcrossPartitions(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** Create Documents Across Partitions ****");
var kirkDocument = await client.CreateDocumentAsync("dbs/myfirstdb", new { userId =
"Kirk", title = "Captain" });
Console.WriteLine("Document 1: {0}", kirkDocument.Resource.SelfLink);
var spockDocument = await client.CreateDocumentAsync("dbs/myfirstdb", new { userId =
"Spock", title = "Science Officer" });
Console.WriteLine("Document 2: {0}", spockDocument.Resource.SelfLink);
}
El primer parámetro aquí es un autoenlace a la base de datos, no una colección específica. Esto no es posible sin un solucionador de particiones, pero con uno funciona a la perfección.
Ambos documentos se guardaron en la base de datos myfirstdb, pero sabemos que Kirk se almacena en la colección de A a M y Spock se almacena en la colección de N a Z, si nuestro RangePartitionResolver funciona correctamente.
Llamemos a estos desde la tarea CreateDocumentClient como se muestra en el siguiente código.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
await CreateCollections(client);
RegisterRangeResolver(client);
await CreateDocumentsAcrossPartitions(client);
}
}
Cuando se ejecuta el código anterior, recibirá el siguiente resultado.
**** Create Documents Across Partitions ****
Document 1: dbs/Ic8LAA==/colls/Ic8LAO2DxAA=/docs/Ic8LAO2DxAABAAAAAAAAAA==/
Document 2: dbs/Ic8LAA==/colls/Ic8LAP12QAE=/docs/Ic8LAP12QAEBAAAAAAAAAA==/
Como se ve, los autoenlaces de los dos documentos tienen diferentes ID de recursos porque existen en dos colecciones separadas.
Con la herramienta de migración de datos de DocumentDB, puede migrar datos fácilmente a DocumentDB. La herramienta de migración de datos de DocumentDB es una utilidad gratuita y de código abierto que puede descargar desde el Centro de descarga de Microsoft.https://www.microsoft.com/
La herramienta de migración admite muchas fuentes de datos, algunas de ellas se enumeran a continuación:
- servidor SQL
- Archivos JSON
- Archivos planos de valores separados por comas (CSV)
- MongoDB
- Almacenamiento de tablas de Azure
- Amazon DynamoDB
- HBase e incluso otras bases de datos de DocumentDB
Después de descargar la herramienta de migración de datos de DocumentDB, extraiga el archivo zip.
Puede ver dos ejecutables en esta carpeta como se muestra en la siguiente captura de pantalla.
Primero, está dt.exe, que es la versión de consola con una interfaz de línea de comandos, y luego está dtui.exe, que es la versión de escritorio con una interfaz gráfica de usuario.
Iniciemos la versión GUI.
Puede ver la página de bienvenida. Haga clic en 'Siguiente' para la página de información de la fuente.
Aquí es donde configura su fuente de datos y puede ver las muchas opciones admitidas en el menú desplegable.
Cuando realiza una selección, el resto de la página de información de la fuente cambia en consecuencia.
Es muy fácil importar datos a DocumentDB utilizando la herramienta de migración de datos de DocumentDB. Le recomendamos que utilice los ejemplos anteriores y utilice también los otros archivos de datos.
DocumentDB proporciona los conceptos para controlar el acceso a los recursos de DocumentDB. El acceso a los recursos de DocumentDB se rige por un token de clave maestra o un token de recursos. Las conexiones basadas en tokens de recursos solo pueden acceder a los recursos especificados por los tokens y no a otros recursos. Los tokens de recursos se basan en los permisos de los usuarios.
Primero crea uno o más usuarios, y estos se definen a nivel de base de datos.
Luego, crea uno o más permisos para cada usuario, en función de los recursos a los que desea permitir que cada usuario acceda.
Cada permiso genera un token de recurso que permite el acceso completo o de solo lectura a un recurso determinado y que puede ser cualquier recurso de usuario dentro de la base de datos.
Los usuarios se definen a nivel de la base de datos y los permisos se definen para cada usuario.
Los usuarios y los permisos se aplican a todas las colecciones de la base de datos.
Echemos un vistazo a un ejemplo simple en el que aprenderemos cómo definir usuarios y permisos para lograr seguridad granular en DocumentDB.
Comenzaremos con un nuevo DocumentClient y consultaremos la base de datos myfirstdb.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'myfirstdb'").AsEnumerable().First();
collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
"SELECT * FROM c WHERE c.id = 'MyCollection'").AsEnumerable().First();
var alice = await CreateUser(client, "Alice");
var tom = await CreateUser(client, "Tom");
}
}
A continuación se muestra la implementación de CreateUser.
private async static Task<User> CreateUser(DocumentClient client, string userId) {
Console.WriteLine();
Console.WriteLine("**** Create User {0} in {1} ****", userId, database.Id);
var userDefinition = new User { Id = userId };
var result = await client.CreateUserAsync(database.SelfLink, userDefinition);
var user = result.Resource;
Console.WriteLine("Created new user");
ViewUser(user);
return user;
}
Step 1- Creemos dos usuarios, Alice y Tom como cualquier recurso que creamos, construimos un objeto de definición con el Id deseado y llamamos al método create y en este caso llamamos CreateUserAsync con el SelfLink de la base de datos y el userDefinition. Obtenemos el resultado de cuya propiedad de recurso obtenemos el objeto de usuario recién creado.
Ahora para ver estos dos nuevos usuarios en la base de datos.
private static void ViewUsers(DocumentClient client) {
Console.WriteLine();
Console.WriteLine("**** View Users in {0} ****", database.Id);
var users = client.CreateUserQuery(database.UsersLink).ToList();
var i = 0;
foreach (var user in users) {
i++;
Console.WriteLine();
Console.WriteLine("User #{0}", i);
ViewUser(user);
}
Console.WriteLine();
Console.WriteLine("Total users in database {0}: {1}", database.Id, users.Count);
}
private static void ViewUser(User user) {
Console.WriteLine("User ID: {0} ", user.Id);
Console.WriteLine("Resource ID: {0} ", user.ResourceId);
Console.WriteLine("Self Link: {0} ", user.SelfLink);
Console.WriteLine("Permissions Link: {0} ", user.PermissionsLink);
Console.WriteLine("Timestamp: {0} ", user.Timestamp);
}
Step 2- Llame a CreateUserQuery, en el UsersLink de la base de datos para recuperar una lista de todos los usuarios. Luego, recorralos y vea sus propiedades.
Ahora tenemos que crearlos primero. Entonces, digamos que queríamos permitirle a Alice permisos de lectura / escritura para la colección MyCollection, pero Tom solo puede leer documentos en la colección.
await CreatePermission(client, alice, "Alice Collection Access", PermissionMode.All,
collection);
await CreatePermission(client, tom, "Tom Collection Access", PermissionMode.Read,
collection);
Step 3- Cree un permiso en un recurso que sea una colección MyCollection, por lo que necesitamos obtener ese recurso como SelfLink.
Step 4 - Entonces crea un Permiso. Todo en esta colección para Alice y un Permiso. Lee sobre esta colección para Tom.
A continuación se muestra la implementación de CreatePermission.
private async static Task CreatePermission(DocumentClient client, User user,
string permId, PermissionMode permissionMode, string resourceLink) {
Console.WriteLine();
Console.WriteLine("**** Create Permission {0} for {1} ****", permId, user.Id);
var permDefinition = new Permission {
Id = permId,
PermissionMode = permissionMode,
ResourceLink = resourceLink
};
var result = await client.CreatePermissionAsync(user.SelfLink, permDefinition);
var perm = result.Resource;
Console.WriteLine("Created new permission");
ViewPermission(perm);
}
Como ya debería esperar, lo hacemos creando un objeto de definición para el nuevo permiso, que incluye un Id y un permisoMode, que es Permission.All o Permission.Read, y el SelfLink del recurso que se está protegiendo con el permiso.
Step 5 - Llame a CreatePermissionAsync y obtenga el permiso creado de la propiedad del recurso en el resultado.
Para ver el permiso creado, a continuación se muestra la implementación de ViewPermissions.
private static void ViewPermissions(DocumentClient client, User user) {
Console.WriteLine();
Console.WriteLine("**** View Permissions for {0} ****", user.Id);
var perms = client.CreatePermissionQuery(user.PermissionsLink).ToList();
var i = 0;
foreach (var perm in perms) {
i++;
Console.WriteLine();
Console.WriteLine("Permission #{0}", i);
ViewPermission(perm);
}
Console.WriteLine();
Console.WriteLine("Total permissions for {0}: {1}", user.Id, perms.Count);
}
private static void ViewPermission(Permission perm) {
Console.WriteLine("Permission ID: {0} ", perm.Id);
Console.WriteLine("Resource ID: {0} ", perm.ResourceId);
Console.WriteLine("Permission Mode: {0} ", perm.PermissionMode);
Console.WriteLine("Token: {0} ", perm.Token);
Console.WriteLine("Timestamp: {0} ", perm.Timestamp);
}
Esta vez, es una consulta de permisos contra el enlace de permisos del usuario y simplemente enumeramos cada permiso devuelto para el usuario.
Eliminemos los permisos de Alice y Tom.
await DeletePermission(client, alice, "Alice Collection Access");
await DeletePermission(client, tom, "Tom Collection Access");
A continuación se muestra la implementación de DeletePermission.
private async static Task DeletePermission(DocumentClient client, User user,
string permId) {
Console.WriteLine();
Console.WriteLine("**** Delete Permission {0} from {1} ****", permId, user.Id);
var query = new SqlQuerySpec {
QueryText = "SELECT * FROM c WHERE c.id = @id",
Parameters = new SqlParameterCollection {
new SqlParameter { Name = "@id", Value = permId }
}
};
Permission perm = client.CreatePermissionQuery(user.PermissionsLink, query)
.AsEnumerable().First();
await client.DeletePermissionAsync(perm.SelfLink);
Console.WriteLine("Deleted permission {0} from user {1}", permId, user.Id);
}
Step 6 - Para eliminar permisos, consulte por Id. De permiso para obtener el SelfLink y luego utilice el SelfLink para eliminar el permiso.
A continuación, eliminemos los propios usuarios. Eliminemos ambos usuarios.
await DeleteUser(client, "Alice");
await DeleteUser(client, "Tom");
A continuación se muestra la implementación de DeleteUser.
private async static Task DeleteUser(DocumentClient client, string userId) {
Console.WriteLine();
Console.WriteLine("**** Delete User {0} in {1} ****", userId, database.Id);
var query = new SqlQuerySpec {
QueryText = "SELECT * FROM c WHERE c.id = @id",
Parameters = new SqlParameterCollection {
new SqlParameter { Name = "@id", Value = userId }
}
};
User user = client.CreateUserQuery(database.SelfLink, query).AsEnumerable().First();
await client.DeleteUserAsync(user.SelfLink);
Console.WriteLine("Deleted user {0} from database {1}", userId, database.Id);
}
Step 7 - Primera consulta para obtener su SelfLink y luego llamar a DeleteUserAsync para eliminar su objeto de usuario.
A continuación se muestra la implementación de la tarea CreateDocumentClient en la que llamamos a todas las tareas anteriores.
private static async Task CreateDocumentClient() {
// Create a new instance of the DocumentClient
using (var client = new DocumentClient(new Uri(EndpointUrl), AuthorizationKey)) {
database = client.CreateDatabaseQuery("SELECT * FROM c WHERE c.id =
'myfirstdb'").AsEnumerable().First();
collection = client.CreateDocumentCollectionQuery(database.CollectionsLink,
"SELECT * FROM c WHERE c.id = 'MyCollection'").AsEnumerable().First();
ViewUsers(client);
var alice = await CreateUser(client, "Alice");
var tom = await CreateUser(client, "Tom");
ViewUsers(client);
ViewPermissions(client, alice);
ViewPermissions(client, tom);
string collectionLink = client.CreateDocumentCollectionQuery(database.SelfLink,
"SELECT VALUE c._self FROM c WHERE c.id = 'MyCollection'")
.AsEnumerable().First().Value;
await CreatePermission(client, alice, "Alice Collection Access", PermissionMode.All,
collectionLink);
await CreatePermission(client, tom, "Tom Collection Access", PermissionMode.Read,
collectionLink);
ViewPermissions(client, alice);
ViewPermissions(client, tom);
await DeletePermission(client, alice, "Alice Collection Access");
await DeletePermission(client, tom, "Tom Collection Access");
await DeleteUser(client, "Alice");
await DeleteUser(client, "Tom");
}
}
Cuando se compile y ejecute el código anterior, recibirá el siguiente resultado.
**** View Users in myfirstdb ****
Total users in database myfirstdb: 0
**** Create User Alice in myfirstdb ****
Created new user
User ID: Alice
Resource ID: kV5oAC56NwA=
Self Link: dbs/kV5oAA==/users/kV5oAC56NwA=/
Permissions Link: dbs/kV5oAA==/users/kV5oAC56NwA=/permissions/
Timestamp: 12/17/2015 5:44:19 PM
**** Create User Tom in myfirstdb ****
Created new user
User ID: Tom
Resource ID: kV5oAALxKgA=
Self Link: dbs/kV5oAA==/users/kV5oAALxKgA=/
Permissions Link: dbs/kV5oAA==/users/kV5oAALxKgA=/permissions/
Timestamp: 12/17/2015 5:44:21 PM
**** View Users in myfirstdb ****
User #1
User ID: Tom
Resource ID: kV5oAALxKgA=
Self Link: dbs/kV5oAA==/users/kV5oAALxKgA=/
Permissions Link: dbs/kV5oAA==/users/kV5oAALxKgA=/permissions/
Timestamp: 12/17/2015 5:44:21 PM
User #2
User ID: Alice
Resource ID: kV5oAC56NwA=
Self Link: dbs/kV5oAA==/users/kV5oAC56NwA=/
Permissions Link: dbs/kV5oAA==/users/kV5oAC56NwA=/permissions/
Timestamp: 12/17/2015 5:44:19 PM
Total users in database myfirstdb: 2
**** View Permissions for Alice ****
Total permissions for Alice: 0
**** View Permissions for Tom ****
Total permissions for Tom: 0
**** Create Permission Alice Collection Access for Alice ****
Created new permission
Permission ID: Alice Collection Access
Resource ID: kV5oAC56NwDON1RduEoCAA==
Permission Mode: All
Token: type=resource&ver=1&sig=zB6hfvvleC0oGGbq5cc67w==;Zt3Lx
Ol14h8pd6/tyF1h62zbZKk9VwEIATIldw4ZyipQGW951kirueAKdeb3MxzQ7eCvDfvp7Y/ZxFpnip/D G
JYcPyim5cf+dgLvos6fUuiKSFSul7uEKqp5JmJqUCyAvD7w+qt1Qr1PmrJDyAIgbZDBFWGe2VT9FaBH o
PYwrLjRlnH0AxfbrR+T/UpWMSSHtLB8JvNFZNSH8hRjmQupuTSxCTYEC89bZ/pS6fNmNg8=;
Timestamp: 12/17/2015 5:44:28 PM
**** Create Permission Tom Collection Access for Tom ****
Created new permission
Permission ID: Tom Collection Access
Resource ID: kV5oAALxKgCMai3JKWdfAA==
Permission Mode: Read
Token: type=resource&ver=1&sig=ieBHKeyi6EY9ZOovDpe76w==;92gwq
V4AxKaCJ2dLS02VnJiig/5AEbPcfo1xvOjR10uK3a3FUMFULgsaK8nzxdz6hLVCIKUj6hvMOTOSN8Lt 7
i30mVqzpzCfe7JO3TYSJEI9D0/5HbMIEgaNJiCu0JPPwsjVecTytiLN56FHPguoQZ7WmUAhVTA0IMP6 p
jQpLDgJ43ZaG4Zv3qWJiO689balD+egwiU2b7RICH4j6R66UVye+GPxq/gjzqbHwx79t54=;
Timestamp: 12/17/2015 5:44:30 PM
**** View Permissions for Alice ****
Permission #1
Permission ID: Alice Collection Access
Resource ID: kV5oAC56NwDON1RduEoCAA==
Permission Mode: All
Token: type=resource&ver=1&sig=BSzz/VNe9j4IPJ9M31Mf4Q==;Tcq/B
X50njB1vmANZ/4aHj/3xNkghaqh1OfV95JMi6j4v7fkU+gyWe3mJasO3MJcoop9ixmVnB+RKOhFaSxE l
P37SaGuIIik7GAWS+dcEBWglMefc95L2YkeNuZsjmmW5b+a8ELCUg7N45MKbpzkp5BrmmGVJ7h4Z4pf D
rdmehYLuxSPLkr9ndbOOrD8E3bux6TgXCsgYQscpIlJHSKCKHUHfXWBP2Y1LV2zpJmRjis=;
Timestamp: 12/17/2015 5:44:28 PM
Total permissions for Alice: 1
**** View Permissions for Tom ****
Permission #1
Permission ID: Tom Collection Access
Resource ID: kV5oAALxKgCMai3JKWdfAA==
Permission Mode: Read
Token: type=resource&ver=1&sig=NPkWNJp1mAkCASE8KdR6PA==;ur/G2
V+fDamBmzECux000VnF5i28f8WRbPwEPxD1DMpFPqYcu45wlDyzT5A5gBr3/R3qqYkEVn8bU+een6Gl j
L6vXzIwsZfL12u/1hW4mJT2as2PWH3eadry6Q/zRXHAxV8m+YuxSzlZPjBFyJ4Oi30mrTXbBAEafZhA 5
yvbHkpLmQkLCERy40FbIFOzG87ypljREpwWTKC/z8RSrsjITjAlfD/hVDoOyNJwX3HRaz4=;
Timestamp: 12/17/2015 5:44:30 PM
Total permissions for Tom: 1
**** Delete Permission Alice Collection Access from Alice ****
Deleted permission Alice Collection Access from user Alice
**** Delete Permission Tom Collection Access from Tom ****
Deleted permission Tom Collection Access from user Tom
**** Delete User Alice in myfirstdb ****
Deleted user Alice from database myfirstdb
**** Delete User Tom in myfirstdb ****
Deleted user Tom from database myfirstdb
En este capítulo, aprenderemos a visualizar los datos almacenados en DocumentDB. Microsoft proporcionó la herramienta Power BI Desktop que transforma sus datos en imágenes enriquecidas. También le permite recuperar datos de varias fuentes de datos, fusionar y transformar los datos, crear informes y visualizaciones potentes y publicar los informes en Power BI.
En la última versión de Power BI Desktop, Microsoft también ha agregado soporte para DocumentDB en el que ahora puede conectarse a su cuenta de DocumentDB. Puede descargar esta herramienta desde el enlace,https://powerbi.microsoft.com
Echemos un vistazo a un ejemplo en el que visualizaremos los datos de terremotos importados en el último capítulo.
Step 1 - Una vez descargada la herramienta, inicie el escritorio de Power BI.
Step 2 - Haga clic en la opción 'Obtener datos' que se encuentra en la pestaña Inicio en el grupo Datos externos y mostrará la página Obtener datos.
Step 3 - Seleccione la opción Microsoft Azure DocumentDB (Beta) y haga clic en el botón 'Conectar'.
Step 4 - Ingrese la URL de su cuenta, base de datos y colección de Azure DocumentDB desde la que desea visualizar los datos y presione Aceptar.
Si se conecta a este punto final por primera vez, se le pedirá la clave de la cuenta.
Step 5 - Ingrese la clave de cuenta (clave principal) que es única para cada cuenta de DocumentDB disponible en Azure Portal y luego haga clic en Conectar.
Cuando la cuenta se conecte correctamente, recuperará los datos de la base de datos especificada. El panel Vista previa muestra una lista de elementos de registro, un documento se representa como un tipo de registro en Power BI.
Step 6 - Haga clic en el botón 'Editar' que abrirá el Editor de consultas.
Step 7 - En el Editor de consultas de Power BI, debería ver una columna Documento en el panel central, haga clic en el expansor en el lado derecho del encabezado de la columna Documento y seleccione las columnas que desea mostrar.
Como puede ver, tenemos la latitud y la longitud como columnas separadas, pero visualizamos los datos en forma de coordenadas de latitud y longitud.
Step 8 - Para hacer eso, haga clic en la pestaña 'Agregar columna'.
Step 9 - Seleccione Agregar columna personalizada que mostrará la siguiente página.
Step 10- Especifique el nombre de la nueva columna, digamos LatLong y también la fórmula que combinará la latitud y la longitud en una columna separada por una coma. La siguiente es la fórmula.
Text.From([latitude])&", "&Text.From([longitude])
Step 11 - Haga clic en Aceptar para continuar y verá que se agrega la nueva columna.
Step 12 - Vaya a la pestaña Inicio y haga clic en la opción 'Cerrar y aplicar'.
Step 13- Puede crear informes arrastrando y soltando campos en el lienzo de informes. Puede ver a la derecha que hay dos paneles: uno de Visualizaciones y el otro de Campos.
Creemos una vista de mapa que muestre la ubicación de cada terremoto.
Step 14 - Arrastre el tipo visual del mapa desde el panel Visualizaciones.
Step 15- Ahora, arrastre y suelte el campo LatLong desde el panel Campos a la propiedad Ubicación en el panel Visualizaciones. Luego, arrastre y suelte el campo de magnitud a la propiedad Valores.
Step 16 - Arrastre y suelte el campo de profundidad en la propiedad Saturación de color.
Ahora verá el mapa visual que muestra un conjunto de burbujas que indican la ubicación de cada terremoto.