Marc Rubiño

ASP.NET, C#, AJAX.NET, JavaScript, etc.

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 

 

 

 

Posted: 24/2/2011 9:33 por Marc Rubiño | con 7 comment(s) |
Archivado en: ,,
Comparte este post:

Comentarios

Pedro Santos ha opinado:

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.

# February 24, 2011 12:05 PM

Marc Rubiño ha opinado:

Gracias Pedro por el aporte, yo también he sufrido estos problemas.

Tendremos que comparar Drivers para ver cual da mejor resultado ;-)

Saludos

# February 24, 2011 12:30 PM

Unai ha opinado:

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

# February 24, 2011 9:31 PM

Marc Rubiño ha opinado:

Muy interesante aportación.

Gracias Unai

# February 24, 2011 10:27 PM

andres ha opinado:

Que opinión tienen por aquí de RavenDB?

# March 1, 2011 2:23 AM

Alberto Basalo ha opinado:

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.

# March 1, 2011 3:42 PM

Marc Rubiño ha opinado:

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 www.mongodb.org/.../viewpage.action

Hay un webcast de Hadi sobre CouchDB en secondnug  geeks.ms/.../webcast-couchdb-para-net.aspx

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

Saludos ;-)

# March 1, 2011 10:02 PM