RavenDB (II)- Los documentos

Tal y como ya dijimos en la anterior entrada, RavenDB es una base de datos documental,  y esto, está llevado a su extremo. Una de las primeras cosas que me llamaron la atención de RavenDB es que en realidad, físicamente, en RavenDB, no hay otra cosa que documentos, es decir, al contrario que en otros sistemas del mismo tipo como MongoDB, no existen, físicamente por lo menos, el concepto de colecciones, más adelante veremos como en realidad el concepto de colección es lógico es decir, documentos que comparten un atributo de metadata.

Una  de las características principales que también nombramos es que Raven es RESTfull y por lo tanto podremos mediante la identificación de recursos y verbos HTTP acceder a los documentos almacenados. Según vayamos avanzando en nuestras entradas iremos viendo los verbos y el contenido de cada tipo de petición. Por ahora, con el fin de ir mostrando distintos ejemplos iremos a nuestro Raven Management Studio y utilizaremos la opción de crear un juego de documentos de ejemplo, tal y como podemos ver en la siguientes figura:

sampledata

Una vez creados los documentos de ejemplo, podremos observar como RavenDB pone a nuestra disposición un conjunto de recursos principales para almacenar los documentos, estos recursos, o database layout como se conoce en la documentación, son los siguientes:

http://[servidor-raven]/docs : Nos permite acceder a todos los documentos de la base de datos por defecto. Si, raven permite tener múltiples bases de datos, pero, sino hacemos el ejercicio de crearlas siempre tenemos la “Default Database” como punto de trabajo. Si haces esta petición utilizando IE recuerda que este no entiende el application/json y por lo tanto seguramente te pida descargar un archivo (para evitarlo se puede tocar una entrada de registro). Si miramos el resultado de esta petición con Fiddler veríamos algo como lo siguiente:

HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
Raven-Server-Build: 531
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Thu, 01 Dec 2011 18:47:28 GMT
Content-Length: 12447

[{"AlbumArtUrl":"/Content/Images/placeholder.gif","Artist":{"Id":"artists/113","Name":"Os Paralamas Do Sucesso"},"Genre":{"Id":"genres/7","Name":"Latin"},"Price":8.99,"Title":"Arquivo II","CountSold":1,"@metadata":{"Raven-Entity-Name":"Albums","Raven-Clr-Type":"MvcMusicStore.Models.Album, Mvc Music Store","Content-Type":"application/json; charset=utf-8","Last-Modified":"2011-12-01T18:38:30.4410000+01:00","@id":"albums/626","@etag":"00000000-0000-0100-0000-000000000100","Non-Authoritive-Information":false}},{....}]

 

Fíjese la estructura para el primer documento devuelto, se ha omitido toda la salida por simplicidad, por el servidor, la cual está formada por una serie de propiedades principales, el Id, la metadata, detalles del documento, ultima modificación, un etag etc  y la propia información del mismo, el cuerpo o los datos. Más grafícamente, el documento en cuestión seria tal y como se puede ver en las siguientes imagenes extraidas de RavenDB Management Studio.

 

23

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Si se fija en la imagen de la derecha, dentro de la metadata del documento, tenemos una propiedad llamada Raven-Entity-Name.  Es esta propiedad la que nos permite indicar que un documento se categoriza en una determinada colección, en nuestro caso Albums, recuerde que unos párrafos atrás deciamos que físicamente no existe el concepto de colección, aquí tiene la respuesta de cómo hace el Management Studio para categorizarnos esta información.

 

http://[servidor-raven]/indexes: En este recurso se alamacenarán los documentos referidos a los indices, estáticos o dinámicos, que tengamos en RavenDb. Por ahora no vamos a hablar sobre esto, intentaremoms ir paso a paso y lo tocaremos en su profundidad cuando hablemos sobre consultas.

 

http://[servidor-raven]/static : Recurso dedicado a los attachements, al igual que los índices lo veremos en cuanto toque.image_thumb_1

 

¿Como se diseña un documento?

Si es la primera vez que usted trabaja con una base de datos documental seguramente empezará pagando el peaje del mundo relacional, una tendencia en la que todos hemos caido la primera vez que nos enfrentamos a esta otra forma de trabajar. Generalmente, el primer error que cometemos es la tendencia a crear documentos como filas de una tabla, es decir elementos planos de datos. Poco a poco, nos damos cuenta que esos documentos pueden contener otros documentos, de hecho deberían.  Una buena forma de pensar en estos documentos es igualando los limites del mismo al concepto que tenemos en DDD para definir los agregados, Aggreagte Root, de un modelo de dominio:

“Definition: A cluster of associated objects that are treated as a unit for the purpose of data changes. External references are restricted to one member of the Aggregate, designated as the root. A set of consistency rules applies within the Aggregate's boundaries.”

De hecho, hay alguna característica importante de RavenDB que hacen que este patrón, Aggregate, sea mucho más sencillo de implementar, mucho más que utilizando ORM’s como EF o NH. Hablaremos un poco más adelante sobre esto.

Por supuesto, un documento puede referenciar a otros documentos, de igual forma que Eric Evans en la anotación sobre Agregados comenta:

“Choose one Entity to be the root of each Aggregate, and control all access to the objects inside the boundary through the root. Allow external objects to hold references to root only”

Cuando veamos el trabajo en la parte cliente nos pararemos, y veremos con detalle, estos puntos que acabamos de comentar, como mantener los invariantes de nuestros agregados y, como se realizan las referencias entre documento y como las mismas son manejadas en RavenDB.

 

 

Vale… pero empezamos ya a trabajar!!

 

Seguro que llegados hasta aquí ya todos tenemos ganas de ponernos con lo nuestro, que es .NET, por lo tanto, empezaremos a ver como que son los documenetos en el mundo .NET y como podemos trabajar con ellos. Lógicamente utilizaremos el API cliente y por lo tanto algunos elementos sobre los que no hemos hablado, aunque mencionaremos su propósito, no se preocupe si no se explican en detalle porque en futuras entradas seguro que se tratan de la forma debida. Por ahora, trabajaremos, por simplificar, con una aplicación de consola a la que le agregaremos las referencias de RavenDB de cliente, recuerde que en los directorios de instalación teníamos una carpeta llamada Client, si trabaja en .NET 3.5 lógicamente debe de usar la carpeta Client3.5.

 

Ahora que ya tenemos un proyecto con las referencias correspondientes vamos a empezar a crear un ejemplo sencillo. Para RavenDB, un documento no es más que una clase .NET o un tipo dinámico cualquiera, por ejemplo, los siguientes elementos son documentos correctos para RavenDB.

2

1

 

 

 

 

 

 

 

 

 

 

Para empezar a investigar que es lo que se extrae de estos documentos, vamos a escribir la siguientes lineas de código, las cuales, nos permitirán realizar un guardado en la base de datos de estos documentos. Si tiene experiencia con NHibernate, EF seguramente le resulte bastante similar este código al de cualquier guardado con NH/EF. Permitame recordarle que por ahora no nos pararemos demasiado en el código, lo haremos más adelante, permítame ir centrándonos primero en los documentos.

 

using (var store = new DocumentStore() { Url = "http://localhost" }.Initialize())
{
    using (var session = store.OpenSession())
    {
        var order = new Order()
        {
            OrderDate = DateTime.Now,
            Address = new ShippingAddress()
            {
                City ="the city",
                ZipCode ="the zip code",
                AddressLine1 ="the address line"
            }
        };
 
        session.Store(order);
        session.SaveChanges();
    }
}

Si revisáramos con una traza de fiddler el contenido de la petición anterior veríamos algo similar a lo siguiente (en realidad también hay otra serie de operaciones referidas al calculo de la idéntidad de este documento, que serán exáminadas en futuras entradas):

 

POST http://ravendbserver/bulk_docs HTTP/1.1
Accept-Encoding: deflate,gzip
Content-Type: application/json; charset=utf-8
Host: portblackcode
Content-Length: 270
Expect: 100-continue

[{"Key":"orders/2049","Method":"PUT","Document":{"OrderDate":"2011-12-05T10:55:03.7964347+01:00","Address":{"City":"the city","ZipCode":"the zip code","AddressLine1":"the address line"}},"Metadata":{"Raven-Entity-Name":"Orders","Raven-Clr-Type":"RavenI.Order, RavenI"}}]

 

De esto pueden estraerse algunas conclusiones o elementos que deberemos de examinar en más detalle.

  • Las operaciones de inserción de documentos se hacen sobre un RequestReponder que trabaja en la URI http://ravendbserver/bulk_docs con el verbo POST.
  • La información de metadata se extrae de la información del tipo que estamos incluyendo, así por ejemplo el nombre de la propiedad Raven-Entity-Name que nos permite calificar a nuestra colección es una pluralización de la entidad. Esta pluralización está marcada por el tipo Raven.Client.Util.Inflector, aunque como todo el RavenDB, podemos modificarla escribiendo nuestra propia convención de pluralización y asignándola como podemos ver a continuación:
store.Conventions.FindTypeTagName = (type) =>
{
    //this is trivial and not for production implementation
    return type.Name + "s";
};
  • Al documentose le ha asignado una clave de forma automática  “orders/2049” que tendremos que investigar como y que mecanismo se ha utilizado para generarla. Por lo tanto, para consultar este documento podría hacer lo siguiente http://ravendbserver/docs/orders/2049

 

Si ahora, en vez de utilizar order, utilizamos un tipo anónimo ( igual con lo dinámicos) como el que vimos en las imagenes anteriores tendríamos una payload hacia el servidor como el siguiente:

 

POST http://ravendbserver/bulk_docs HTTP/1.1
Accept-Encoding: deflate,gzip
Content-Type: application/json; charset=utf-8
Host: portblackcode
Content-Length: 239
Expect: 100-continue

[{"Key":null,"Method":"PUT","Document":{"OrderDate":"2011-12-05T11:17:02.5348622+01:00","Address":"the shipping address"},"Metadata":{"Raven-Clr-Type":"<>f__AnonymousType0`2[[System.DateTime, mscorlib][System.String, mscorlib]], RavenI"}}]

 

Y de esta información podemos extraer las siguientes conclusiones:

 

  • Los documentos representados como un tipo anónimo no son categorizados en ninguna colección.
  • Por defecto su clave es null y por lo tanto se delega en el servidor la creación de una, RavenDB utiliza un Guid para representar la clave de este documento, así por ejemplo la consulta del mismo se podría hacer de la siguiente forma http://ravendbserver/docs/69851d86-58bf-4915-a6c8-2c9b5ae991f7

 

 

Bueno, hasta aquí llegamos con la segunda entrada, en la siguiente, veremos como hace RavenDB para decidir que elementos de una entidad son utilizados como parte de la información de un documento, propiedades publicas o no, fields publicos o no etc etc etc.. a mayores también hablaremos acerca de la identidad y del trabajo con la metadata.

 

Saludos

Unai

Published 5/12/2011 11:25 por Unai
Comparte este post:
http://geeks.ms/blogs/unai/archive/2011/12/05/ravendb-ii-los-documentos.aspx

Comentarios

# re: RavenDB (II)- Los documentos

Me gusta el enfoque que le está dando, sobre todo porque estás bajando a un nivel inferior al client API y resulta bastante interesante.

Una duda sobre el final, ¿qué utilidad tendría almacenar objetos anónimos? y ¿cómo los devuelve luego RavenDB? ¿Como dynamic? Lo digo porque el clr-type que almacena sólo tiene sentido (y sólo es visible) dentro del assembly en el que está declarado el tipo anónimo, así que luego no puede reconstruirse desde otro assembly.

Monday, December 5, 2011 9:32 PM por Juanma

# RavenDB(III) Sobre la metadata y la serialización de los documentos

En esta tercera de las entradas sobre RavenDB , si lo deseas puedes consultar las entariores aquí

Friday, December 9, 2011 1:42 PM por O bruxo mobile

# RavenDB(V) Actualizaciones, concurrencia, patch y otras hierbas

En esta quinta entrega de la serie, puede ver las anteriores entradas aquí, I ,- II - III y IV , vamos

Thursday, December 15, 2011 9:06 PM por O bruxo mobile

# RavenDB (IV) La identidad de los documentos

En las anteriores entradas hemos trabajado bastante con los documentos, desde una pequeña introducción

Tuesday, December 20, 2011 11:36 PM por O bruxo mobile

# DDD, agregados y NoSQL

En la segunda entrada que se publico en este blog sobre RavenDB se hizo una pequeña mención, no demasiado

Monday, January 30, 2012 8:36 PM por O bruxo mobile