MongoDB con Norm

Últimamente se ha puesto de moda las bases de datos NoSql y realmente es una buena alternativa si no necesitas una base de datos relacional y es mucho más potente que utilizar por ejemplo un fichero XML.

 MongoDB es una base de datos documental no existe el concepto de tabla, solo contamos con colecciones de objetos en formato JSon y de código abierto. Una solución escalable y de alto rendimiento que nos permite trabajar con índices, replicación y alta disponibilidad. MongoDB está realizado en C++ pero su cliente soporta múltiples Drivers de lenguajes de programación, tanto por mongodb.org como por la comunidad de desarrolladores. Para .Net tiene drivers para C# y F#.

Para mis ejemplo utilizaré Norm un driver para C# que facilita la interacción con las colecciones, la serialización/deserialización de objetos JSOn como documentos “BSON” a tipos .NET y la utilización de LinQ-To-Mongo. Otra de las utilidades que he utilizado es mongoVUE para administrar nuestras bases de datos de una forma gráfica.

 

Con esta utilidad podéis ver los datos en formato árbol o en JSon.

 

 

La Instalación

La instalación es muy simple:

  1. Crear los directorios “C:MongoDBdata” y “C:MongoDBlogs”
  2. Copiar los ficheros de la instalación MongoDB
  3. En el directorio “C:MongoDBbin” ejecutar: “mongod –dbpath C:MongoDBdata –directoryperdb –install –logpath C:MongoDBlogslog.txt” “En Windows 7, ejecutar el CMD como administrador para no tener problemas”
  4. Arrancar el servicio de MongoDB

El Modelo

Una de las ventajas de Norm es que podemos utilizar nuestras entidades sin necesidad de realizar grandes cambios, el único requerimiento es utilizar el objeto ObjectId para que MongoDb lo utilice como identificador de los registros.

 [DataContract]
    public class Persona
    {
        public ObjectId Id { get; set; }
        [DataMember]
        public string Nombre { get; set; }
        [DataMember]
        public string Apellidos { get; set; }
        [DataMember]
        public DateTime Fecha { get; set; }
        [DataMember]
        public string Poblacion { get; set; }
        [DataMember]
        public int Hermanos { get; set; }
        [DataMember]
        public List Aficiones { get; set; }

    }
    [DataContract]
    public class Aficion
    {
         [DataMember]
        public string Nombre { get; set; }
         [DataMember]
        public string Descripcion { get; set; }
    }

La Conexión

Para conectar con nuestra base de datos tenemos que especificar el nombre de la base de datos, el servidor el puerto y un string con las opciones.

private Mongo mongo;
public RepositoyNomgoDB()
{
   mongo = new Mongo("EjMongoDB", "localhost", "27017", string.Empty);
}

Las Consultas

Para todas nuestras consultas podemos utilizar objetos anónimos o consultas LinQ. Lo primero que tenemos que hacer e obtener la colección que queremos utilizar, como si fuera una tabla de una base de datos relacional.

var collection = (MongoCollection)mongo<Personas>.GetCollection("Personas");

Una vez que tenemos la colección podemos utilizar las típicas sentencias CRUD.

 collection.Insert(persona);
 collection.Delete(persona);
 collection.Save(persona);
 collection.UpdateOne(persona.Id, persona);

Ahora ya podemos realizar nuestras consultas utilizando la forma que nos sea más cómoda;

Buscar un Resultado:

//NoRM anonymous objects:
var persona = mongo.GetCollection<Personas>("Personas")
                             .FindOne(new { Nombre = "Marc" });
//NoRM Linq:
var personalinQ = mongo.GetCollection<Personas>("Personas")
                                                 .AsQueryable()
                                  .Where(per => per.Nombre == "Marc"
                                && per.Apellidos == "Rubiño").ToList();

Buscar Varios Resultados o paginar los resultados:

//NoRM anonymous objects:
var persona = mongo.GetCollection<Personas>("Personas").Find(new { },
                                new { Fecha = OrderBy.Descending }, 2, 1)
                                 .ToList();
//NoRM Linq:
var persona = mongo.GetCollection<Personas>("Personas").AsQueryable()
                                 .OrderByDescending(per => per.Fecha)
                                  .Skip(1)
                                  .Take(2).ToList();

Operadores Condicionales:

 //Mayor que
var persona = mongo.GetCollection<Personas>("Personas").AsQueryable()
                            .Where(per => per.Hermanos > 3).ToList();
//Igual o Mayor
var persona = mongo.GetCollection<Personas>("Personas").AsQueryable()
                             .Where(per => per.Hermanos >= 3).ToList();
//Diferente
var persona = mongo.GetCollection<Personas>("Personas").AsQueryable()
                              .Where(per => per.Hermanos != 3).ToList();
//En
var persona = mongo.GetCollection<Personas>("Personas").Find(
                   new { Aficiones = Q.In("Futbol", "Música") }).ToList();
//NO En
var persona = mongo.GetCollection<Personas>("Personas").Find(
             new { Aficiones = Q.NotIn("Futbol", "Música") }).ToList();
//Existe
var persona = mongo.GetCollection<Personas>("Personas").Find(
                           new { Apellidos = Q.Exists(true) }).ToList();
//OR
var persona = mongo.GetCollection<Personas>("Personas")
                             .Find(Q.Or(new { Nombre = "Marc" },
                             new { Aficiones = "Futbol" })).ToList();

Distinto y Count:

//Count
 var persona = mongo.GetCollection<Personas>("Personas")
                        .Count(new { Poblacion = "Cambrils" });
//Distinct
var persona = mongo.GetCollection<Personas>("Personas")
                                 .Distinct("Aficiones");

Con expresiones Regulares:

//Empieza por Ma
 var persona = mongo.GetCollection<Personas>("Personas").AsQueryable()
                         .Where(per => Regex.IsMatch(per.Nombre, "^Ma"))
                          .ToList();

Ya podemos añadir y obtener los registros desde nuestra base de datos NoSql de Personas

 

Espero que en la próxima entrega pueda hacer un ejemplo más específico para una aplicación ASP.NET.

CrossPosting: http://mrubino.net 

 

 

 

7 comentarios en “MongoDB con Norm”

  1. Muy bueno el post.

    Comparto algunas de mis experiencias con NORM. He empezado por seguir los mismos pasos que tu. Pero he encontrado un par de temas en NORM que no me acaba de convencer.

    Primaro si cambias la estructura de tus entidades, añadiendo por ejemplo un nuevo campo, NORM ya nos es capaz de leer las entidades ya existentes el la collection. Esto va un poco en contra de la flexibilidad que te da mongoDb al no imponer un esquema de BBDD tan rígido como una BBDD relacional.

    Otro tema que he encontrado es que dependiendo de donde hagas cambios el tipo de dado almacenado cambia. Mira esta pregunta que hice en StackOverflow http://bit.ly/gdh6N5.

    Por estos problemas he desestimado NORM y he decidido usar el driver de 10gen.

  2. Yo, que llevo tiempo con Mongo me gustaría hacer la msima acolación que Pedro, lo mejor es directamente lso drivers de 10gen, además, el mismo mapeo de entidades lo puedes hacer utilizando los atributos de serialización Bson como BSonId,BSonElement etc…

    P.D: Por cierto, Kristina, miembro de 10gen, acaba de publicar hace poco un libro dedicado solamente a escalabilidad ( replicaset y sharding en mongodb)

    Unai

  3. Yo he visto esta comparación http://goo.gl/ddNUC, y al final los comentarios son favorables a Mongo. Aquí http://goo.gl/FCUin hay otra comparativa que incluye también a CouchDB. Por cierto, no he visto driver ni código para descargar de 10gen, ¿como se consigue?
    Tema muy interesante y con poca info en castellano. gracias Marc.

  4. Actualmente estoy en un proyecto con CQRS y NoSQl y me pareció un tema muy interesante para comentar.

    Otra comparación sobre MongoDB y CouchDB http://www.mongodb.org/pages/viewpage.action?pageId=11960372

    Hay un webcast de Hadi sobre CouchDB en secondnug http://geeks.ms/blogs/secondnug/archive/2010/10/28/webcast-couchdb-para-net.aspx

    Yo diria que el driver de 10gen se puede descargar desde https://github.com/mongodb/mongo-csharp-driver

    Saludos 😉

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *