Mostrando entradas con la etiqueta MongoDB. Mostrar todas las entradas
Mostrando entradas con la etiqueta MongoDB. Mostrar todas las entradas

martes, 21 de octubre de 2014

Instalación del driver de MongoDB en Python

Para desarrollar aplicaciones Python basadas en la base de datos MongoDB

, es necesario instalar PyMongo, el driver oficial para Python

Instalación en Linux

La forma más sencilla de instalar PyMongo es mediante el siguiente comando:

$ easy_install pymongo

Si no lo tienes, puede instalarlo mediante el siguiente comando:

sudo apt-get install python-setuptools

Otra forma de instalarlo es mediante el gestor de paquetes pip. Si no lo tienes instalado, puedes adquirirlo mediante el siguiente comando:

$ sudo apt-get install python-pip

A continuación instalamos el driver mediante el siguiente comando:

$ pip install pymongo

Instalación en Windows

Para Windows disponemos de instaladores estándar. Basta con descargar el archivo .exe del driver más reciente de:

https://pypi.python.org/pypi/pymongo/#downloads

Y lanzar el instalador.

Probando PyMongo

Nada mejor que un ejemplo práctico para comprobar el funcionamiento de PyMongo. Para ello, crearemos un fichero llamado demoMongoDB.py, con el siguiente código:

from pymongo import MongoClient

conexion = MongoClient('localhost', 27017)
basedatos = conexion.pruebas
coleccion = basedatos.pruebas

print "Num. documentos:", coleccion.count()

for doc in coleccion.find():
   print doc

En la primera línea importamos el driver pymongo y la clase MongoClient, la cual gestiona una conexión cliente a la base de datos. A continuación creamos una conexión a una base de datos MongoDB localizada en nuestra propia máquina (localhost) y en el puerto estándar (27017). Después, desde la conexión, abrimos la base de datos pruebas. Después, desde la base de datos abierta, abrimos la colección pruebas. A continuación, visualizamos el número de documentos que tiene la colección. Por último, visualizamos todos los documentos de la colección.

Más info:

Instalación del driver de MongoDB para PHP

Instalación en Linux

Antes de proceder a la instalación y configuración del driver de MongoDB en Linux, es necesario tener instalado antes pecl. Si no lo tienes instalado, utiliza el siguiente comando:

sudo apt-get install php5-dev php5-cli php-pear

Para utilizar MongoDB desde PHP, primero hay que descargar el driver correspondiente en la siguiente URL:

http://pecl.php.net/package/mongo

Una vez descargado, procedemos a descomprimir el archivo y a compilar y a instalar el driver mediante los siguientes comandos:

$ tar zxvf mongodb-mongodb-php-driver-.tar.gz
$ cd
$ phpize
$ ./configure
$ make all
$ sudo make install

Debería mostrar un mensaje como el siguiente:

Installing shared extensions: /usr/local/lib/php/extensions/no-debug-zts-20121212/

La instalación debería configurar el archivo php.ini, apuntando al archivo mongo.so a través del parámetro extensions. Para verificarlo, primero localizamos el archivo mongo.so mediante el siguiente comando:

$ sudo find / -name mongo.so

Ese archivo debería estar localizado en el directorio

/usr/local/lib/php/extensions/no-debug-zts-<fecha>

Para verificar si se ha configurado correctamente, ejecutaremos el siguiente comando:

$ php -i | grep extension_dir

El resultado debería ser similar al siguiente:

extension_dir => /usr/local/lib/php/extensions/no-debug-zts-20121212 => /usr/local/lib/php/extensions/no-debug-zts-20121212

Después, modificar el archivo php.ini y configurar el siguiente parámetro:

extension=mongo.so

Por último, reiniciar el servidor de Apache.

Instalación en Windows

La instalación en Windows es más sencilla. Lo primero que hay que hacer es descargar la última versión del driver en la siguiente URL:

https://s3.amazonaws.com/drivers.mongodb.org/php/index.html

A continuación, descomprimir el archivo descargado y copiar el archivo php_mongo.dll en el directorio de extensiones PHP, el cual, normalmente, se llama ext.

Después, modificar el archivo php.ini y añadir la siguiente línea:

extension=php_mongo.dll

Por último, reiniciar el servidor de Apache.

domingo, 19 de octubre de 2014

Fechas en MongoDB

MongoDB es una base de datos muy potente a la hora de utilizar valores de fecha. En este artículo analizaremos cómo gestionar correctamente las fechas y cómo encontrar los datos en base a fechas.

Agregar fechas

La forma más sencilla de insertar una fecha es la siguiente:

> db.coleccion.insert({"fecha" : new Date()})

El comando anterior agrega un nuevo documento a la colección, con un campo fecha que contendrá la fecha y hora actuales. Si listamos el contenido del documento, obtendremos un resultado como el siguiente:

> db.coleccion.find()

{ "_id" : ObjectId("5443e87e5894b090804c822e"), "fecha" : ISODate("2014-10-19T16:36:14.197Z") }

El tipo de dato ISODate contendrá la fecha en formato internacional (año-mes-día), seguido de la hora con precisión de milésimas de segundo.

Para agregar una fecha específica sin especificar la hora, se puede utilizar la función Date() con el siguiente formato:

> db.coleccion.insert({fecha: new Date("2014, 10, 21")})

Si queremos agregar una fecha y hora concretas, podemos utilizar el tipo ISODate() como función para especificar el valor:

> db.coleccion.insert({fecha: ISODate("2014-10-19T18:56:20.197Z")})

Búsqueda de fechas

Para hacer una búsqueda exacta (por fecha y hora), podemos utilizar el siguiente formato:

> db.coleccion.find({"fecha" : ISODate("2014-10-20T22:00:00Z")})

{ "_id" : ObjectId("5443f41b5894b090804c8234"), "fecha" : ISODate("2014-10-20T22:00:00Z") }

Si deseamos buscar todos los documentos a partir de una fecha específica:

> db.coleccion.find({"fecha" : {"$gt" : ISODate("2014-10-18T00:00:00")}})

También podemos utilizar la siguiente sintaxis:

> db.coleccion.find({"fecha" : {"$gt" : new Date("2014-10-18")}})

En ambos casos indicamos a la función find() (encontrar) que compare el campo "fecha" con el valor a buscar, que es un nuevo documento que contiene el operador "$gt" (greater than ó mayor que) y la fecha a partir de la cual debe hacer coincidir el resultado.

Los operadores condicionales utilizados por MongoDB para evaluar las condiciones de los valores a encontrar son los siguientes:

  • $gt: greater than (mayor que)
  • $gte: greater than or equal (mayor o igual que)
  • $lt: less than (menor que)
  • $lte: less than or equal (menor o igual que)
  • $ne: not equal (distinto de)
  • $in: in (dentro de(un array)
  • $nin: not in (no dentro de (un array))

Por ejemplo, si deseamos encontrar aquellos documentos que se encuentren entre dos fechas dadas:

> start = ISODate("2014-10-18T00:00:00Z")
ISODate("2014-10-18T00:00:00Z")
> end = ISODate("2014-10-20T00:00:00Z")
ISODate("2014-10-20T00:00:00Z")
> db.coleccion.find({"fecha" : {"$gte" : start, "$lte" : end}})

Al encadenar una lista de criterios a evaluar, por defecto asumirá que se aplica una operación lógica "$and". Lo anterior sería lo mismo que este comando:

> db.coleccion.find({"$and" : [{"fecha" : {"$gte" : start}}, {"fecha" : {"$lte" : end}}]})

Si queremos omitir el rango anterior utilizaríamos el operador lógico "$or":

> db.coleccion.find({"$or" : [{"fecha" : {"$lt" : start}}, {"fecha" : {"$gt" : end}}]})

Los operadores lógicos utilizados por MongoDB son los siguientes:

  • $and: Todas las condiciones del array se deben cumplir
  • $or: Se debe cumplir, al menos, una condición del array
  • $not: Invierte la condición.

Puede ocurrir que deseemos obtener documentos que se encuentren entre una lista de posibles coincidencias. Para ello, utilizaremos el operador condicional "$in", seguido de un array con la lista de valores a evaluar:

> db.coleccion.find({"fecha" : {"$in" : [ISODate("2014-10-20T22:00:00Z"), ISODate("2014-10-19T18:56:20.197Z"), ISODate("2014-10-15T18:56:20.197Z")]}})

En el caso de que quisiéramos cualquier documento excepto los que se encuentran en la lista, utilizaríamos el operador condicional "$nin".

Optimización de las búsquedas

Para que nuestras búsquedas sean mucho más rápidas y eficientes, necesitaríamos indexar la colección por el campo fecha:

> db.coleccion.ensureIndex({"fecha" : 1})
{
   "createdCollectionAutomatically" : false,
   "numIndexesBefore" : 1,
   "numIndexesAfter" : 2,
   "ok" : 1
}

El comando ensureIndex permite crear un índice en base a la lista de campos especificados. Con un valor 1, indicamos que el campo esté ordenado de alfabéticamente o de menor a mayor. Si el valor fuese -1, el orden sería a la inversa.

martes, 10 de julio de 2012

Primeros pasos en MongoDB

Introducción
MongoDB es una base de datos opensource que está teniendo mucha aceptación por las prestaciones que ofrece en entorno Web 2.0, aunque puede ser utilizada en cualquier tipo de situaciones. MongoDB acerca el sistema de almacenamiento y gestión de datos tipo clave/valor, puliendo la diferencia con respecto a los sistemas de bases de datos relacionales. Este sistema permite una tremenda rapidez y escalabilidad, frente a la funcionalidad de los sistemas de bases de datos tradicionales.

Las principales características de MongoDB son las siguientes:
- Software abierto
- Escalable
- Alto rendimiento
- Alta disponibilidad (puede trabajar en modo maestro-esclavo)
- Orientado a documentos (no es relacional)
- Simplicidad basada en esquemas de tipo JSON
- Consultas dinámicas
- Completo soporte de índices, incluyendo índices secundarios, objetos internos, arrays (cadenas) embebidos, geospacial
- Rápido, actualizaciones in situ.
- Perfilado de consultas
- Almacenamiento eficiente de datos binarios en objetos largos, tales como vídeos o fotografías
- Replicación y soporte a prueba de fallos
- Auto fragmentación para escalabilidad a nivel de nube.
- Agregación compleja mediante MapReduce
- Acceso y gestión mediante drivers en multitud de lenguajes de programación: C, C++, C#, .NET, Java, JavaScript, PHP, Phyton, Ruby, Perl, etc.
- Soporte, formación y consultoría.

En este artículo (que espero sea el primero de muchos), se realiza una pequeña introducción a MongoDB.

Orientación a documentos
La información en MongoDB no se almacena en tablas (con sus correspondiente filas y columnas), si no en colecciones (estructuradas o no) cuyos datos forman parejas de clave y valor. Estos datos se almacenan con un estilo JSON, en formato binario llamado BSON. Un ejemplo de este estilo se puede apreciar en el siguiente documento:

{ nombre: ‘Rafael’,
apellidos: ‘Hernamperez Martin’,
fechaingreso: Date(’03-22-2010’),
seleccion: [‘Aprenda MongoDB’,’Flex 4 en una semana’,’AJAX para Dummies’],
comentarios: [{autor: ‘adan3000’, comentario: ‘Buena eleccion’},
{autor: ‘majopero’, comentario: ‘Te has pasado’, puntuacion:5}
]
}


Una colección sería similar a una tabla, y un documento sería similar a una fila. Habría que distinguir claramente, pues la colección puede tener documentos con estructura similar pero no igual (algunos documentos podrían tener más o menos claves). Asimismo, una única clave podría tener una colección de valores (array o cadena, como en el caso de la clave “seleccion"), o bien podría ser también una sub-colección con sus respectivos documentos (como en el caso de la clave “comentarios”).

La sintaxis en formato JSON es muy fácil de entender, eliminando los problemas de errores que pueden ocurrir en el formato XML (ambos son muy sinérgicos), además de reducir el tamaño de la información a transportar.

Este formato es utilizado no sólo para entenderlos, sino también para gestionarlos y realizar consultas en sus campos internos. Por ejemplo:

db.compras.find({'nombre':'Rafael'})

Nota: si falla, probar con comillas dobles

Esta consulta localizaría todos los documentos dentro de la colección “compras” cuya clave “nombre” tenga el valor “Rafael”.

Otro ejemplo:

db.compras.find({'comentarios.autor':'adan3000'})

Esta consulta localizaría todos los documentos dentro de la colección “compras” cuyo comentario haya sido realizado por el “autor” llamado “adan3000”.


Instalación
Para nuestros propósitos utilizaremos Windows como plataforma de operaciones. También puede instalarse en sistemas operativos OS X, Linux y Solaris (ver instrucciones en http://www.mongodb.org/display/DOCS/Quickstart)

En primer lugar hay que crear la siguiente ruta de directorio: “c:\data\db”. Esta ruta es la ruta por defecto para los archivos de bases de datos.

A continuación descargar el archivo zip (ocupa apenas 13MB) de la siguiente URL:
http://www.mongodb.org/display/DOCS/Downloads
y descomprimirlo en la ruta que deseemos (por ejemplo en C:\ donde creará un subdirectorio llamado “mongodb-winxx-xxxx”).


Arrancar un servidor MongoDB
MongoDB se ejecuta principalmente en su consola. Para ello se accede al modo consola DOS de Windows (pulsar AltGr+R, escribir “cmd” (sin las comillas) y Aceptar).

Acceder al directorio “bin” de donde se descomprimió el fichero zip (ejemplo):

cd c:\mongodb-win32-i386-1.2.4\bin

Ahora, para lanza MongoDB por defecto, ejecutar el ejecutable:

mongod

Con esto, MongoDB accederá a las bases de datos almacenadas en el directorio
c:\data\db y usando el puerto 27017. Si se desea cambiar el directorio de ficheros de bases de datos o el puerto, usar los siguientes parámetros:

mongod --dbpath [rutadirectorio] --port [puerto]

Si acaso saltase el cortafuegos, desbloquear el acceso para poder usarlo.

Para parar la base de datos, pulsar Ctrl+C. Con ello, MongoDB esperará hasta que todas las operaciones se hayan completado, guardando las últimas transacciones y cerrando los ficheros.

Existen otros parámetros que pueden ser usados por el motor de MongoDB:
-h (--help): Muestra información sobre los parámetros permitidos
--logpath rutafichero: Especifica fichero de log
--logappend: añade al log, en lugar de sobreescribirlo
--cpu: log periódico de la CPU y de los tiempos de entrada/salida
--fork: ejecución como demonio
--auth: Activa la seguridad
--noauth: Desactiva la seguridad (por defecto)
--nohttpinterface: Desactiva la interfaz http (localhost:27018)
--master: Designa este servidor como maestro (entorno de alta disponibilidad)
--slave: Designa este servidor como esclavo (entorno de alta disponibilidad)
--autoresync: Resincronización automática del servidor esclavo.
--source servidor:puerto: Para un servidor esclavo especifica dónde está el servidor maestro para la replicación

Una forma sencilla de arrancar el servidor MongoDB sin repetir los parámetros, es añadiendo éstos a un fichero de configuración. El formato del fichero sería el siguiente:

#comentario
parametro1 = valor1
parametro2 = valor 2


Para lanzar el servidor usando este fichero, ejecutar:

mongod –config ficheroconfiguración
mongod –f ficheroconfiguración


Consola de MongoDB
Una vez arrancado el servidor, podemos utilizar la consola de MongoDB para interactuar con las bases de datos. Para ello, acceder al modo consola DOS de Windows (pulsar AltGr+R, escribir “cmd” (sin las comillas) y Aceptar).

Acceder al directorio “bin” de donde se descomprimió el fichero zip (ejemplo):

cd c:\mongodb-win32-i386-1.2.4\bin

Ahora, lanzar la consola de MongoDB:

mongo

(nótese que no tiene la "d" final).

En esta nueva consola, nos permitirá escribir los comandos necesarios para interactuar con el servidor (mongod), de tal forma que podamos gestionar documentos y estructuras o acceder a la información (entre muchas acciones). Cada comando ha de estar acompañado por un “Enter” para su ejecución.

Por defecto se conecta a una base de datos llamada “test” (por defecto).

Para mostrar la base de datos en uso:
db

Para autentificar un usuario (sólo cuando se ejecuta el servidor en modo seguridad):
db.auth(usuario,contraseña)

Para salir de la consola MongoDB, escribir el comando
exit

Para conseguir ayuda sobre los comandos disponibles, escribir el comando
help

Para mostrar las bases de datos disponibles:
show dbs

Para mostrar las colecciones de la base de datos actual:
show collections

Para mostrar los usuarios de la base de datos actual:
show users

Para utilizar una base de datos:
use nombrebasedatos

Para mostrar ayuda sobre los métodos de base de datos:
db.help()

Para mostrar ayuda sobre los métodos para la colección foo:
db.foo.help()

Para mostrar los objetos en una colección foo:
db.foo.find()

Referencias
Sitio oficial de MongoDB: http://www.mongodb.org


Safe Creative #1003225810323

Conceptos básicos de MongoDB

Filosofía de almacenamiento en MongoDB

La filosofía de las bases de datos NOSQL suele ser chocante para todos los que llevan años trabajando en bases de datos relacionales. El no tener el concepto de una tabla, o de una integridad referencial con su relación de clave maestra a clave foránea, se hace difícil imaginar cómo puede funcionar y cómo pueden relacionarse y entenderse los datos.

MongoDB tiene el concepto de la información almacenada como clave/valor. Estos pares se almacenan en forma de documento u objeto dentro de una colección. Podemos imaginar un símil entre clave/valor como campo/valor, entre un objeto o documento y una fila, y entre colección y tabla. Este concepto puede ayudar a entender un poco mejor este sistema, pero no hay que olvidar que es un símil, no una equiparación.

Un documento u objeto (los dos términos se refieren a lo mismo), aunque se asemeje a una fila, en realidad no tiene nada que ver, pues en una base de datos relacional, cada fila tiene una organización estructurada común entre todas las filas. En MongoDB, cada fila puede tener su propia estructura, tener más o menos campos, e incluso tener campos que en sí mismos son arrays (contener varios valores) o incluso contener otro documento como valor, o incluso un array de documentos. Esto, entendido bien, nos puede dar una idea de la potencia que ello implica, pues es posible tener en un mismo objeto, de manera incrustada, otros objetos, sin necesidad de implicar a la base de datos en varias tablas, definir claves y relacionar dichas claves. Por ejemplo, imaginemos la clásica relación “Categoría” y “Producto”. En un sistema de base de datos tradicional, se definirían dos tablas:

Tabla categoría:
- idcategoria: integer: PRIMARY KEY
- nombrecategoria: char(30)

Tabla producto:
- idproducto: integer: PRIMARY KEY
- nombreproducto: char(30)
- idcategoria: integer

Internamente, el gestor de base de datos debe estar constantemente velando para que los datos clave sean únicos, no nulos y que no violan las reglas de integridad referencial, realizando complejas operaciones de índices y actualización de éstos. Estas operaciones son transparentes para los usuarios y desarrolladores. Es cómodo, pero sobrecargan los tiempos de CPU y penalizan otras operaciones que pueden ser más importantes.

En una base de datos MongoDB se requeriría únicamente una colección de objetos, cada uno de los cuales puede tener una estructura propia (no tiene por qué ser la misma).

{producto: “Perdiz escabechada”, categoria:[“carne”,”conserva”]}
{producto:”Naranja”, categoria:”fruta”]}
{producto:”Sal”}


De este simple ejemplo se pueden extraer algunas reflexiones:
- El almacenamiento físico gana mucho, al no estar supeditada a una estructura fija y definida. Se pueden omitir claves (campos) si se desea, y los campos de texto ocupan sólo el número de caracteres que contiene, no un tamaño fijo.
- Se prescinde de campos id, que dificultan el entendimiento de los datos.
- Se centraliza todo en una única colección, y no añade la dificultad de las relaciones.
- Un producto puede no estar asociado a una categoría, o bien estar asociado a varias categorías. En este último caso, en una base de datos relacional, requeriría de una tercera tabla intermedia con la colección de relaciones, y el trabajo extra en el código para reconstruir las mismas.
- Si bien el control de la redundancia en las categorías es un esfuerzo por parte del código, en el caso de una base de datos relacional, también habría que hacer un esfuerzo en código cuando se determina si hay redundancia por los errores que emite la base de datos (clave duplicada, infracción de integridad…).
- El modo de almacenamiento es más natural para la máquina y para el humano, pues toda la información está en el mismo documento, en lugar de repartido. Esto evita al código repartir la información (al guardar) y de reunirla (al acceder).
- En un modelo relacional, utilizar id’s reduce el espacio de almacenamiento en tablas extensas (ocupa mucho menos un número que un texto), pero complica el desarrollo y el acceso. MongoDB reduce y optimiza espacio de almacenamiento en los campos de texto, supliendo este espacio e incluso mejorándolo. Asimismo, el código para guardar o acceder a la información es mucho más simple (no hay que realizar relaciones (los típicos join o el uso de varias consultas a varias tablas) ni realizar varias actualizaciones por cada una de las tablas involucradas).

Otro ejemplo de almacenamiento en un documento u objeto sería el siguiente:
{ nombre: ‘Rafael’,
apellidos: ‘Hernamperez Martin’,
fechaingreso: Date(’03-22-2010’),
seleccion: [‘Aprenda MongoDB’,’Flex 4 en una semana’,’AJAX para Dummies’],
comentarios: [{autor: ‘adan3000’, comentario: ‘Buena eleccion’},
{autor: ‘majopero’, comentario: ‘Te has pasado’, puntuacion:5}
]
}


La clave “comentarios” es un array de documentos. Un documento puede contener, asimismo, documentos asociados a una clave. Es lógico suponer que el nivel de anidamiento puede ser tan profundo como uno desee.

El formato de datos utilizado por MongoDB es JSON, una especificación estándar para representar la información. Es similar a la de XML, pero reduce el contenido a expresar y haciendo más legible y natural la interpretación de la información. El último documento en formato XML sería el siguiente:
<documento>
  <nombre>Rafael</nombre>
  <apellidos>Hernamperez Martin</apellidos>
  <fechaingreso>03-22-2010</fechaingreso>
  <seleccion>
    <titulo>Aprenda MongoDB</titulo>
    <titulo>Flex 4 en una semana</titulo>
    <titulo>AJAX para Dummies</titulo>
  </seleccion>
  <comentarios>
    <comment autor=”adan3000” comentario=”Buena elección”/>
    <comment autor=”majopero” comentario=”Te has pasado” puntuación=”5”/>
  </comentarios>
</documento>


Alguno se estará preguntando cómo mantener la consistencia de los datos en las aplicaciones. Por ejemplo, en una aplicación es conveniente evitar al usuario teclear la categoría, pudiendo seleccionar una ya predeterminada en una lista para asegurar que sea unívoca y que no haya multitud de referencias a un mismo valor que esté redundante porque se diferencia en una letra o está mal escrito. Se puede crear una colección de categorías, en un formato muy similar al de una tabla (usando documentos con una única clave), y usar ésta como se haría normalmente, o incluso añadir un documento en nuestra colección cuya clave sea un array de valores posibles. Aunque su estructura no tenga nada que ver con el resto de documentos almacenados en la misma. Se accede a dicho documento dentro de la colección y se extraen los posibles valores. La primera opción es más sencilla y legible. La última es más óptima en cuanto almacenamiento y gestión por parte del motor de base de datos (trabaja en la misma colección y comparte los mismos ficheros). Otra solución intermedia, y a la vez elegante, sería definir una colección exclusiva para almacenar documentos que contengan series de datos maestros (categorías, tipos, etc.)

Otra de las ventajas de utilizar este sistema de información, es que no tienes tantas limitaciones a la hora de escalar la información si los requisitos cambian (cosa que ocurre, pues nadie conoce el futuro). En bases de datos relacionales, añadir nuevos campos a una tabla, o una nueva tabla relacionada o maestra y normalizar una base de datos que lleva ya tiempo en producción, es cuanto menos un engorro y un agujero de problemas.

Una vez se entienden estos sencillos conceptos, el adaptar nuestros desarrollos a este tipo de bases de datos es sencillo, e incluso nos beneficiaremos de una mayor legilibilidad y rapidez.


Paso a paso
El movimiento se demuestra andando, y para aprender a caminar en MongoDB procederemos a realizar, paso a paso, un ejemplo práctico. El propósito del mismo es tener una colección de datos personales llamada “agenda”, dentro de una base de datos llamada “ejemplo”. En el ejemplo se verá cómo crear la base de datos, la colección y los datos, y a continuación se verá como realizar consultas a dichos datos.

Arranque del servidor y de la consola MongoDB

Primeramente, arrancar el servidor de MongoDB desde una consola DOS (para Linux, los pasos son muy similares):

cd c:\mongodb-win32-i386-1.2.4\bin
mongod


A continuación, arrancar la consola de MongoDB (dbShell) en otra consola DOS:

cd c:\mongodb-win32-i386-1.2.4\bin
mongo



Creación de la base de datos y de la colección

Aunque no se haya creado aún la base de datos, utilizar ésta (asumirá que se va a utilizar para ser creada):

> use ejemplo
switched to db ejemplo


A continuación crear un objeto que contendrá un documento, el cual se insertará en la colección “agenda” (aún no creada):

> doc = {nombre: "Rafael", apellido1: "Gonzalez", apellido2: "Martin", telefono: "912406790"}

{
"nombre" : "Rafael",
"apellido1" : "Gonzalez",
"apellido2" : "Martin",
"telefono" : "912406790"
}


El siguiente paso es añadir este objeto (documento) a la colección “agenda”:

> db.agenda.save(doc)

Se puede abreviar el proceso en un solo paso, creando directamente el objeto:

> db.agenda.save({nombre: "Rafael", apellido1: "Gonzalez", apellido2: "Martin", telefono: "912406790"})

Esto equivaldría a la sentencia SQL:

INSERT INTO agenda (nombre, apellido1, apellido2, telefono) VALUES (‘Rafael’, ‘Gonzalez’, ‘Martin’, ‘912406790’)

Automáticamente, MongoDB crea los objetos por asunción. De esta manera, crea la base de datos “ejemplo”, y dentro de ésta crea la colección “agenda”, y dentro de ésta crea y agrega el documento “doc”.


Verificaciones

Para verificar todo lo anterior primero comprobaremos qué base de datos está en uso:

> db
ejemplo


A continuación, listaremos las bases de datos creadas con MongoDB:

> show dbs

admin
ejemplo
local
test


Las bases de datos “admin”, “local” y “test” son las bases de datos que por defecto tiene MongoDB.

La siguiente verificación será comprobar qué colecciones disponemos en la base de datos en uso (“ejemplo”):

> show collections
agenda
system.indexes


La colección “system.indexes” es creada y mantenida de forma automática por MongoDB para el control y gestión de los índices de las colecciones.

Para visualizar solamente las colecciones no internas de MongoDB, se puede usar el siguiente comando:

> db.getCollectionNames()
[ "agenda", "system.indexes" ]


Para conocer a qué base de datos pertenece una determinada colección:

> db.agenda.getDB()
ejemplo


Para conocer qué comandos se puede usar para tratar la colección:

> db.agenda.help()


Consultas a los datos

Para visualizar todos los objetos (documentos) de la colección:

> db.agenda.find()
{ "_id" : ObjectId("4ba8a3be5b3d00000000710f"), "nombre" : "Rafael", "apellido1" : "Gonzalez", "apellido2" : "Martin", "telefono" : "912406790" }


Automáticamente, MongoDB asigna un ID único a cada objeto de la colección (clave “_id”).

Vamos a añadir más documentos a la colección:

db.agenda.save({nombre:"Carlos",apellido1:"Sanchez",apellido2:"Sanchez",telefono:"91240890012",email:"carlosss@hotmail.com"}) db.agenda.save({nombre:"Javier",apellido1:"Cristobal",apellido2:"Nombela",telefono:"925407561",email:"javichuc@yahoo.es"})
db.agenda.save({nombre:"Yolanda",apellido1:"Ballesteros",apellido2:"Lopez",telefono:"925406902"})
db.agenda.save({nombre:"Antonio",apellido1:"Blazquez",apellido2:"Fernandez",telefono:"937607812"})
db.agenda.save({nombre:"Jose Miguel", apellido1:"Carvajal", apellido2:"Gomez", telefono:"983679103", email:"picachu234@gmx.com"})
db.agenda.save({nombre:"Juan Carlos", apellido1:"Blazquez", apellido2:"Gil", telefono:"925403789"})


Lista de todos los objetos de la colección:

> db.agenda.find()
{ "_id" : ObjectId("4ba8a3be5b3d00000000710f"), "nombre" : "Rafael", "apellido1" : "Gonzalez", "apellido2" : "Martin", "telefono" : "912406790" }
{ "_id" : ObjectId("4ba8aac55b3d000000007110"), "nombre" : "Carlos", "apellido1" : "Sanchez", "apellido2" : "Sanchez", "telefono" : "91240890012", "email" : "carlosss@hotmail.com" }
{ "_id" : ObjectId("4ba8ab435b3d000000007111"), "nombre" : "Javier", "apellido1" : "Cristobal", "apellido2" : "Nombela", "telefono" : "925407561", "email" : "javichuc@yahoo.es" }
{ "_id" : ObjectId("4ba8ac3f5b3d000000007112"), "nombre" : "Yolanda", "apellido1" : "Ballesteros", "apellido2" : "Lopez", "telefono" : "925406902" }
{ "_id" : ObjectId("4ba8ac865b3d000000007113"), "nombre" : "Antonio", "apellido1" : "Blazquez", "apellido2" : "Fernandez", "telefono" : "937607812" }
{ "_id" : ObjectId("4ba8acde5b3d000000007114"), "nombre" : "Jose Miguel", "apellido1" : "Carvajal", "apellido2" : "Gomez", "telefono" : "983679103", "email" : "picachu234@gmx.com" }
{ "_id" : ObjectId("4ba8af123433000000003118"), "nombre" : "Juan Carlos", "apellido1" : "Blazquez", "apellido2" : "Gil", "telefono" : "925403789" }


Esto equivaldría a la sentencia SQL:

SELECT * FROM agenda

Cuando la colección contiene múltiples objetos será necesario introducir criterios en la búsqueda. El comando “find” permite pasar como parámetros dichos criterios (en formato JSON), los cuales recogen el par (clave/valor) a encontrar. El siguiente comando localiza todos los objetos en cuyo primer apellido sea “Blazquez”:

> db.agenda.find({"apellido1":"Blazquez"})
{ "_id" : ObjectId("4ba8ac865b3d000000007113"), "nombre" : "Antonio", "apellido1" : "Blazquez", "apellido2" : "Fernandez", "telefono" : "937607812" }
{ "_id" : ObjectId("4ba8af123433000000003118"), "nombre" : "Juan Carlos", "apellido1" : "Blazquez", "apellido2" : "Gil", "telefono" : "925403789" }


Lo anterior equivaldría a la sentencia SQL:

SELECT * FROM agenda WHERE apellido1=”Blazquez”

Mediante el siguiente comando sabremos cuántos objetos tiene la colección:

> db.agenda.count()

En un conjunto de datos, para limitar el número de objetos retornados, se especificaría añadiendo el comando limit():

> db.agenda.find().limit(3)
{ "_id" : ObjectId("4ba8a3be5b3d00000000710f"), "nombre" : "Rafael", "apellido1" : "Gonzalez", "apellido2" : "Martin", "telefono" : "912406790" }
{ "_id" : ObjectId("4ba8aac55b3d000000007110"), "nombre" : "Carlos", "apellido1" : "Sanchez", "apellido2" : "Sanchez", "telefono" : "91240890012", "email" : "carlosss@hotmail.com" }
{ "_id" : ObjectId("4ba8ab435b3d000000007111"), "nombre" : "Javier", "apellido1" : "Cristobal", "apellido2" : "Nombela", "telefono" : "925407561", "email" : "javichuc@yahoo.es" }


El comando count() también se puede añadir a find() para saber cuántos objetos ha retornado:

> db.agenda.find({apellido1:"Blazquez"}).count()
2


En el caso de querer visualizar solamente el primero de un conjunto de datos retornados, se usaría el comando findOne():

> db.agenda.findOne({apellido1:"Blazquez"})
{
"_id" : ObjectId("4ba8ac865b3d000000007113"),
"nombre" : "Antonio",
"apellido1" : "Blazquez",
"apellido2" : "Fernandez",
"telefono" : "937607812"
}


Para especificar más criterios, éstos se separan por comas:

> db.agenda.find({"apellido1":"Blazquez","nombre":"Antonio"})
{ "_id" : ObjectId("4ba8ac865b3d000000007113"), "nombre" : "Antonio", "apellido1" : "Blazquez", "apellido2" : "Fernandez", "telefono" : "937607812" }


Su equivalente en SQL sería el siguiente:

SELECT * FROM agenda WHERE apellido1=”Blazquez” AND nombre=”Antonio”

El comando find() retorna realmente un cursor, el cual puede ser utilizado para un acceso más controlado. El siguiente ejemplo se declara una variable que recoge el cursor del comando find(), situándose antes del primer registro. A continuación se declara un bucle while que se repetirá mientras el cursor tenga elementos o no alcance el final (hasNext()). En este bucle se imprimirá, en formato JSON, el objeto actual sobre el cual está situado el cursor. Mediante el comando next(), el cursor avanzará al siguiente objeto.

> var cursor = db.agenda.find()
> while (cursor.hasNext()) { print(tojson(cursor.next())); }
{
"_id" : ObjectId("4ba8a3be5b3d00000000710f"),
"nombre" : "Rafael",
"apellido1" : "Gonzalez",
"apellido2" : "Martin",
"telefono" : "912406790"
}


El siguiente ejemplo, recoge el cursor y accede directamente al tercer objeto del mismo:

> var cursor=db.agenda.find()
> print(tojson(cursor[3]))
{
"_id" : ObjectId("4ba8ac3f5b3d000000007112"),
"nombre" : "Yolanda",
"apellido1" : "Ballesteros",
"apellido2" : "Lopez",
"telefono" : "925406902"
}


La variable “cursor” se podría ver como un array de objetos, por lo que si se quiere acceder a cualquier clave del mismo, se especifica mediante un punto, como si fuera una propiedad:

> print(cursor[3].nombre, cursor[3].apellido1, cursor[3].telefono)
Yolanda Ballesteros 925406902



Safe Creative #1003235820060

MongoDB: Consistencia distribuida. Parte 4

La consistencia eventual hace más fácil el almacenamiento de datos en un centro multi-datos. Hay razones por las que la consistencia eventual es útil para centros multi-datos que no están relatados para la disponibilidad y CAP. Como se mencionó en la parte 3, algunos tipos comunes de particiones de red, tales como la pérdida de un centro de datos entero, son actualmente particiones de red triviales y pueden incluso no tener efecto de disponibilidad de todos modos.

Hay algunas arquitecturas para el almacenamiento de datos en un centro multi-datos:

* DR
* Región simple
* Lecturas locales, escrituras remotas
* Búsqueda inteligente
* Consistencia eventual

DR

Por DR nos referimos a una arquitectura tradicional de continuidad desastre recuperación / negocio. Es bastante simple: servimos cualquier cosa desde un centro de datos, con replicación a una facilidad secundaria que está offline. En un fallo transferimos todo de forma sincronizada.

La disponibilidad puede ser muy alta en este modelo, cuando cualquier asunto sobre el primer centro de datos, incluyendo las particiones de red internas, transferimos sincronizadamente, y con todo el primer centro de datos desactivado, la partición es trivial.

Este modelo funciona bien con consistencia fuerte.

Centro multi datos, Región simple

Esta opción es análoga a usar múltiples centros de datos dentro de una región simple. Amazon y DoubleClick han usado este esquema en el pasado. Tenemos múltiples centros de datos, separados físicamente, pero todo dentro de una región (por ejemplo, el Noroeste). La latencia entre centros de datos es entonces razonable: si permanecemos dentro de un radio de 150 millas, podemos tener transmisiones de cerca de 5 milisegundos. Podríamos tener un anillo de fibra entre digamos, 3 o 4 centros de datos. Como la latencia es razonable, para muchos problemas, una operación WAN aquí está bien. Con una topología de anillo, una partición de red no-trivial es poco probable.

La región simple es útil tanto para arquitecturas de consistencia fuerte como para consistencia eventual. Con un producto del estilo Dynamo, cuando N=W ó N=R, esta es una buena opción, por lo demás cuando se usan múltiples centros de datos tendremos un tiempo de espera grande para confirmar escrituras remotas.

Lecturas locales, Escrituras remotas

Para casos de lectura pesada, esta es una buena opción. Aquí leemos datos eventualmente consistentes (fácil con la mayor parte de productos de base de datos, incluyendo sistemas RDBMS), pero haciendo que todas las escrituras vuelvan a la facilidad maestro sobre la WAN. Un sistema del estilo dynamo en un cento de datos múltiple con un muy alto valor W y un bajo valor R puede ser también considerado de esta manera.

Este patrón debería funciona muy bien para gestión de contenidos tradicionales: publicar no es frecuente, y leer es muy frecuente.

Usar una Red de Entrega de Contenidos (Content Delivery Network (CDN)), con un sitio web origen centralizado sirviendo contenidos dinámicos, es otro ejemplo.

Búsqueda inteligente

Discutimos un poco sobre "Búsqueda Inteligente" (“Intelligent Homing”) en la parte 3. La idea es almacenar la copia maestra de una entidad de datos dada cerca de su usuario.

Esto funciona funciona muy bien si los datos se correlacionan con el usuario, como el perfil del usuario, la bandeja de entrada, etc

Tenemos rápidas escrituras confirmadas localmente. Si un centro de datos se cae completamente, podríamos estar aún a prueba de fallos sobre el estado maestro a cualquier lugar donde haya una réplica.

Consistencia eventual

La consistencia eventual de muchos-escritores nos brinda dos beneficios con centros de datos múltiples:

* altísima disponibilidad en el caso de apagones de red;
* rápidas escrituras confirmadas localmente

En el diagrama de debajo, un cliente de un sistema del estilo dynamo escribe los datos a cuatro servidores (N=4). Sin emabargo, únicamente espera confirmación de las escrituras de dos servidores en su centro de datos local, para mantener la latencia baja en la confirmación de escritura.




Nótese sin embargo que si R+W > N, no podemos tener rápidas lecturas y escrituras locales al mismo tiempo si todos los centros de datos son pares iguales.

Combinaciones

Las combinaciones a menudo tienen sentido. Por ejemplo, es común mezclar DR y Lectura Local / Escritura Remota.

Fuente: http://blog.mongodb.org/post/516567520/on-distributed-consistency-part-4-multi-data-center

Primeros pasos con Python y MongoDB

Una de las mejores características de MongoDB es la multitud de drivers existentes para casi cualquier lenguaje de programación (ver Sección Drivers). Para los que amamos Python, tenemos un driver llamado pymongo, y que está soportado por 10gen, la empresa creadora de MongoDB. El site oficial de este driver lo encontramos en: http://api.mongodb.org/python/1.8.1%2B/index.html

Utilizar Python junto a MongoDB es muy sencillo, pues su sintaxis es muy similar a la de la consola mongo.

Instalación
La instalación de pymongo es sencilla. En Linux, procederemos a ejecutar el siguiente comando:

$ easy_install pymongo

O bien, descargamos el código fuente y lo instalamos desde la consola de Python:

$ git clone git://github.com/mongodb/mongo-python-driver.git pymongo
$ cd pymongo/
$ python setup.py install


Abrir conexión
La conexión se realiza de la siguiente manera:

>>> from pymongo import Connection
>>> conn = Connection() # Conexion local por defecto
>>> conn = Connection('miServidor', 30500) # Conexion remota a puerto 30500


Usar base de datos
Para obtener un objeto que referencia a la base de datos:

>>> db = conn.miBBDD # metodo 1
>>> db = conn['miBBDD'] # metodo 2



Usar una colección
Para obtener la colección con la que trabajar:

>>> coll = db.miColeccion # metodo 1
>>> coll = db['miColeccion'] # metodo 2



Documentos
Los documentos se mapean en Python como un diccionario:

>>> noticia = {"autor": "Rafael Hernamperez",
...   "cuerpo": "Python y MongoDB",
...   "etiquetas": ["Tutorial","Python","MongoDB"]}


Algunos tipos de datos especiales requieren de alguna librería específica, como datetime:

>>> import datetime
>>> noticia = {"autor": "Rafael Hernamperez",
...   "cuerpo": "Python y MongoDB",
...   "etiquetas": ["Tutorial","Python","MongoDB"],
...   "fecha": datetime.datetime.utcnow()}



Insertar documentos
Para insertar un documento:

>>> coll = db.noticias # Coleccion "noticias"
>>> coll.insert(noticia)



Recuperar un documento
Para recuperar un único documento simple (el primero):

>>> coll.find_one({"autor": "Rafael Hernamperez"})


Recuperar varios documentos
Para recuperar todos los documentos de una colección:

>>> for noticia in coll.find():
...    print noticia


Para recuperar todos los documentos (noticias, en este caso) de un autor concreto:

>>> for noticia in coll.find({"autor": "Rafael Hernamperez"})
...    print noticia



Contar documentos
Para contar todos los documentos de una colección:

>>> coll.count()

Para contar todos los documentos de un autor concreto:

>>> coll.find({"autor": "Rafael Hernamperez"}).count()


Consultas de rango
Recupera un determinado rango de documentos, delimitados por condiciones. En este caso, recupera aquellas noticias anteriores a una determinada fecha. El resultado se ordenará por autor:

>>> fecha = datetime.datetime(2010, 9, 28, 0, 0) # 2010/09/38 00:00h
... for noticia in coll.find({"fecha": {"$lt":fecha}}).sort(autor):
...    print noticia



Indexación
Para indexar la colección "noticias", por fecha (de la más reciente a la más antigua) y por autor (en orden alfabético):

>>> from pymongo import ASCENDING, DESCENDING
>>> coll.create_index([("fecha", DESCENDING), ("autor", ASCENDING)])

lunes, 29 de noviembre de 2010

MondonGO: Herramienta ODM para MongoDB y PHP

Las virtudes de MongoDB como base de datos son cada vez más apreciadas por las empresas, ofreciendo servicios Web, Web 2.0 y cloud computing, además de productos basados en las mismas tecnologías o en tecnologías tradicionales. Por otra parte, aparecen herramientas que facilitan la administración de MongoDB, backups, el desarrollo de aplicaciones con MongoDB, etc. En esta ocasión me place presentar una herramienta creada en España, llamada MondonGO, y que seguro será muy apreciada por los desarrolladores de PHP.

MondonGO es un ODM (Object Data Mapper, o un Mapeador de Objetos de Datos), lo que permite mapear la estructura de los documentos de MongoDB automáticamente a objetos en PHP, simplificando enormemente los desarrollos, ya que el acceso, la seguridad y las tareas del mapeo son realizadas automáticamente, optimizando la sencillez y la productividad a la hora de desarrollar aplicaciones PHP usando MongoDB

MondonGO es un desarrollo de código abierto, que se puede descargar libremente desde GitHub.
Enlace a MondonGO: http://mondongo.es

MongoDB: Cómo trabaja una consulta en un entorno fragmentado

Un servidor pequeño. Queremos más capacidad. ¿Qué hacer? Tradicionalmente, podríamos escalar verticalmente con una caja más grande.

Con la fragmentación, en su lugar, escalamos horizontalmente para conseguir la misma huella computacional/almacenamiento/memoria desde servidores pequeños.

He aquí la comparación gráfica de escalabilidad vertical y horizontal:
Una colección fragmentada de MongoDB tiene una clave de fragmento. La colección es particionada en un orden preservando esta clave. En este ejemplo a es nuestra clave de fragmento:

{a:..., b:..., c:... } a es declarado clave de fragmento para la colección

Los metadatos son mantenidos en trozos, los cuales están representados por rangos de claves de fragmentos. Cada trozo es asignado a un fragmento en particular.

RangoFragmento
a en [∞, 2000]2
a en [2000, 2100]8
a en [2100, 2500]3
......
a en [88700, ∞]0

Cuando un trozo se hace demasiado grande, MongoDB automáticamente lo divide, y el balanceador más tarde migrará los trozos cuando sea necesario.

find({a:{$gt:333,$lt:400})

El proceso mongos enruta una consulta a los fragmentos adecuados. Para la consulta anterior, todos los datos posiblemente relevantes están en el fragmento 2, así que la consulta es enviada solamente a aquel nodo, y allí procesada.
A veces, un rango de consulta puede abarcar más de un fragmento, pero muy pocos en total. Esto es razonablemente eficiente.
Las consultas que no involucran las claves de fragmentos serán enviadas a todos los fragmentos como una operación "esparcir/reunir". Esto a veces es correcto. Aquí, tanto en nuestra máquina tradicional como en los fragmentos, haremos una exploracion de tabla igualmente (aproximadamente) costosa en ambas.
De nuevo, una consulta con una clave de fragmento resulta en una operación esparcir/reunir. Sin embargo, en cada fragmento, podemos usar el índice {b:1} para hacer la operación eficiente para dicho fragmento. Tenemos un coste elevado sobre la configuración vertical para el esfuerzo de las comunicaciones desde los procesos mongos para cada fragmento - no demasiado si el número de fragmentos es pequeño (10), pero digamos que muy sustancial en un sistema de 1000 fragmentos.
El término a involucra la clave de fragmento y permite a los procesos mongos enrutar inteligentemente la consulta al fragmento 2. Una vez que la consulta alcanza el fragmento 2, el índice {b:1} puede ser usada para procesar eficientemente la consulta.
Cuando se especifica una ordenación, los fragmentos relevantes ordenan localmente, y los procesos mongos funde los resultados. Así, el uso de recursos de los procesos mongos no es terriblemente alto.
Cuando se usa la replicación (típicamente un conjunto de réplica), simplemente tenemos más de un nodo por fragmento.

Abajo, las flechas indican replicación en entornos tradicionales contra fragmentados.

Fuente original: http://www.mongodb.org/download/attachments/2097354/how+queries+work+with+sharding.pdf

Primeros pasos con Python y MongoDB

Una de las mejores características de MongoDB es la multitud de drivers existentes para casi cualquier lenguaje de programación (ver Sección Drivers). Para los que amamos Python, tenemos un driver llamado pymongo, y que está soportado por 10gen, la empresa creadora de MongoDB. El site oficial de este driver lo encontramos en: http://api.mongodb.org/python/1.8.1%2B/index.html

Utilizar Python junto a MongoDB es muy sencillo, pues su sintaxis es muy similar a la de la consola mongo.

Instalación
La instalación de pymongo es sencilla. En Linux, procederemos a ejecutar el siguiente comando:

$ easy_install pymongo

O bien, descargamos el código fuente y lo instalamos desde la consola de Python:

$ git clone git://github.com/mongodb/mongo-python-driver.git pymongo
$ cd pymongo/
$ python setup.py install


Abrir conexión
La conexión se realiza de la siguiente manera:

>>> from pymongo import Connection
>>> conn = Connection() # Conexion local por defecto
>>> conn = Connection('miServidor', 30500) # Conexion remota a puerto 30500


Usar base de datos
Para obtener un objeto que referencia a la base de datos:

>>> db = conn.miBBDD # metodo 1
>>> db = conn['miBBDD'] # metodo 2



Usar una colección
Para obtener la colección con la que trabajar:

>>> coll = db.miColeccion # metodo 1
>>> coll = db['miColeccion'] # metodo 2



Documentos
Los documentos se mapean en Python como un diccionario:

>>> noticia = {"autor": "Rafael Hernamperez",
...   "cuerpo": "Python y MongoDB",
...   "etiquetas": ["Tutorial","Python","MongoDB"]}


Algunos tipos de datos especiales requieren de alguna librería específica, como datetime:

>>> import datetime
>>> noticia = {"autor": "Rafael Hernamperez",
...   "cuerpo": "Python y MongoDB",
...   "etiquetas": ["Tutorial","Python","MongoDB"],
...   "fecha": datetime.datetime.utcnow()}



Insertar documentos
Para insertar un documento:

>>> coll = db.noticias # Coleccion "noticias"
>>> coll.insert(noticia)



Recuperar un documento
Para recuperar un único documento simple (el primero):

>>> coll.find_one({"autor": "Rafael Hernamperez"})


Recuperar varios documentos
Para recuperar todos los documentos de una colección:

>>> for noticia in coll.find():
...    print noticia


Para recuperar todos los documentos (noticias, en este caso) de un autor concreto:

>>> for noticia in coll.find({"autor": "Rafael Hernamperez"})
...    print noticia



Contar documentos
Para contar todos los documentos de una colección:

>>> coll.count()

Para contar todos los documentos de un autor concreto:

>>> coll.find({"autor": "Rafael Hernamperez"}).count()


Consultas de rango
Recupera un determinado rango de documentos, delimitados por condiciones. En este caso, recupera aquellas noticias anteriores a una determinada fecha. El resultado se ordenará por autor:

>>> fecha = datetime.datetime(2010, 9, 28, 0, 0) # 2010/09/38 00:00h
... for noticia in coll.find({"fecha": {"$lt":fecha}}).sort(autor):
...    print noticia



Indexación
Para indexar la colección "noticias", por fecha (de la más reciente a la más antigua) y por autor (en orden alfabético):

>>> from pymongo import ASCENDING, DESCENDING
>>> coll.create_index([("fecha", DESCENDING), ("autor", ASCENDING)])

MongoDB: Indexación

En MongoDB, la indexación permite optimizar el rendimiento de las consultas, de forma muy similar a la de una base de datos relacional. Los índices se aplican a claves (campos) de nuestros documentos, ordenando sus valores para que la búsqueda sea más eficiente, y manteniendo dicha ordenación de forma constante. Tiene mucho sentido si las consultas sobre la clave es muy frecuente, especialmente si sobre la búsqueda se aplican filtros (mayor que, menor que, etc.), o si la consulta es lenta. También tiene sentido si en las consultas se muestra en un orden determinado.

A pesar de las ventajas del uso de índices, hay que tener en cuenta que los índices toman espacio y ralentizan las escrituras.

El siguiente ejemplo, muestra cómo ordenar una colección por la clave nombre:

db.articulos.ensureIndex({"nombre":1})

El valor 1 indica que la ordenación será en orden ascendente (de menor a mayor valor, o alfabéticamente, de la A a la Z). Para indicar que el orden sea descendente, se indicaría el valor -1. El siguiente ejemplo crea un índice compuesto, ordenando por nombre y por , en orden descendente (de más reciente a más antiguo):

db.articulos.ensureIndex({"nombre":1, "fecha":-1})

Si la clave del índice corresponde a un documento embebido, se ha de indicar la ruta del mismo:

db.articulos.ensureIndex({"comentarios.autor":1})

Los índices únicos indican que los valores de la clave no pueden repetirse:

db.articulos.ensureIndex({"titulo":1}, {unique:true})

Los índices toman un tiempo para realizar su cometido. Si la colección posee muchos datos, este tiempo ralentizaría el resto de operaciones de la base de datos. Para evitar este tiempo de demora, se puede indicar que el índice se realice en background o como operación en segundo plano:

db.articulos.ensureIndex({"nombre":1, "fecha":-1}, {background: true})

Si se desea conocer los índices que posee una colección determinada:

db.articulos.getIndexes()

Para eliminar un índice de una colección:

db.articulos.dropIndex({"nombre":1})


Más información: Os recomiendo ver la presentación de Mike Dirolf, de la cual se ha extraído gran parte de la información mostrada aquí:

MongoDB: Traducir SQL a MapReduce


Fuente: http://nosql.mypopescu.com/post/392418792/translate-sql-to-mongodb-mapreduce

MongoDB: Python y MapReduce

El presente post está inspirado en el artículo "MapReduce with MongoDB and Python", de Marcel Caraciolo, y en el cual veremos cómo implementar la función Map-Reduce mediante Python y MongoDB, donde podremos apreciar su potencial en grandes conjuntos de datos en computación distribuída.

Como ejemplo sencillo e ilustrativo, contaremos la frecuencia de palabras a través de varios documentos. En primer lugar, veremos cómo funciona map-reduce,utilizando una lista de sentencias simples. Para ello, tenemos el siguiente diagrama, en donde las palabras son divididas y agrupadas por la función map, y después reducidas independientemente (agregación) por la función reduce. Nuestra consulta puede estar distribuída en cuatro ordenadores, por lo que su procesamiento es mucho más rápido en tiempo de ejecución. El ejemplo, además, muestra un árbol balanceado, pero podría estar no balanceado o incluso tener alguna redundancia.
Antes de comenzar a desarrollar las funciones map y reduce debes saber que:
1) El motor MapReduce puede invocar funciones reduce de forma iterativa, por lo que éstas deben ser idempotentes:
   for all k,vals : reduce( k, [reduce(k,vals)] ) == reduce(k,vals)
1) Actualmente, el retorno de valores de una función reduce no puede ser un array (ha de ser un objeto o un número)
3) Si necesitas realizar una operación una única vez, utiliza la funión finalize.

Para implementar el código debes utilizar el framework Pymongo, el cual tiene soporte para Map/Reduce. Como ejemplo, el discurso de Obama en 2009 tiene muchas palabras repetidas, como puede apreciarse en la siguiente nube de etiquetas, cuyo tamaño de fuente indica la frecuencia de cada palabra:
MongoDB permite a los clientes enviar las implementaciones JavaScript de map y reduce, las cuales se evaluarán y ejecutarán en el servidor. La función map sería la siguiente (wordMap.js):

function wordMap() {
  // Buscar palabras en el texto del documento
  var palabras = this.text.match(/\w+g);

  if (palabras == null) {
     return;
  }

  for (var i = 0; i < palabras.length; i++) {
    // Emitir cada palabra, con contador de uno
    emit(words[i], {count: 1});
  }
}

MongoDB llamará a la función map por cada documento en la colección que está consultando, y apuntará al documento donde tendrá acceso una clave como text mediante this.text. Esta función no retorna una lista, si no que llama a una función emit que espera ser definida. Los parámetros de esta función (clave, valor), serán agrupados con otros resultados intermedios de otras evaluaciones map que tengan la misma clave (clave, [valor1, valor2]) y pasada a la función reduce (wordReduce.js
function wordReduce(key, values) {

  var total = 0;
  for (var i = 0; i < values.length; i++) {
    total += values[i].count;
  }

  return {count: total};
}

La función reduce ha de reducir una lista de un tipo dado a un valor simple del mismo tipo; debe transsitivo para que no tenga problemas sobre cómo están agrupados los elementos mapeados.

A continuación, el código del cliente Pymongo que pasa las funciones map/reduce al servidor:

MongoDB: Un ejemplo de MapReduce

Conceptos de MapReduce
MapReduce es una característica importante comprendida por MongoDB. Este framework fue creado por Google para dar solución a la computación paralela sobre grandes colecciones de datos en sistemas distribuídos. El concepto se basa en dos funciones, map y reduce, que se aplican sobre datos estructurados en formato de pares clave-valor.

La función map (mapeo) toma uno de estos pares en un dominio de datos, y retorna una lista de pares en un dominio diferente. Se aplica en paralelo por cada elemento de la entrada de datos, produciendo la lista de pares por cada llamada, juntando todos los pares con la misma clave de todas las listas y los agrupa, creando un grupo por cada clave.

La función reduce (reducción) se aplica paralelamente a cada grupo, generando una colección de valores para cada dominio, produciendo un valor (o varios) en cada llamada.

Básicamente, MapReduce transforma una lista de pares clave-valor en una lista de valores.


Un ejemplo
Para comprender cómo funciona MapReduce, vamos a ver un ejemplo práctico. Para ello, voy a utilizar uno ya hecho por Kristina Chodorow, una de las principales creadoras de MongoDB.

Imaginemos que tenemos una colección posts, que almacena los artículos de nuestro blog. Un documento en esta colección podría tener esta estructura:
La clave tags es un array de etiquetas, que permiten categorizar cada artículo. Y sobre esta clave vamos a basar el ejemplo de MapReduce, como por ejemplo, conocer las etiquetas más populares, dando un resultado como éste:
La función map emitirá cada etiqueta (tag), y la contará en la función reduce.

La función map es la siguiente:
Lo primero que hace es comprobar si existe una clave llamada tags, para evitar errores. A continuación realiza un bucle sobre esta clave (por cada elemento del array), emitiendo su nombre y un contador de 1.

La función reduce inicializa un contador a 0 y le añade cada elemento del array current. Al final retorna el contador final:
Para ejecutar ésto, invocaremos al comando mapreduce:
Los parámetros facilitados son:
- mapreduce: Se facilita la colección sobre la que extraer los datos (posts).
- map: Nombre de la función que realizará el mapeo.
- reduce: Nombre de la función que realizará la reducción.
- out: Colección donde se pondrá el resultado.

Finalmente, consultamos la colección tags para mostrar los resultados:


Fuentes consultadas
Concepto de MapReduce en Wikipedia: http://es.wikipedia.org/wiki/MapReduce
Artículo "Contar etiquetas", por Kristina Chodorow: http://cookbook.mongodb.org/patterns/count_tags/

Comparativa MongoDB con otras Bases de datos NoSQL

He encontrado en myNoSQL algunas tablas comparativas de MongoDB con respecto a otras bases de datos NoSQL, creadas por Alex Popescu.

Bases de datos orientadas a documento
La primera tabla compara tres bases de datos orientadas a documento: MongoDB, CouchDB y RavenDB (echo en falta una columna para OrientDB).

  MongoDB CouchDB RavenDB
Documentos
FormatoBSONJSONJSON
MetadataNoSistemaSistema + personalizado
VersionadoNoPlugin incluído
AdjuntosGridFS
Map/ReduceJavaScript + otrosJavaScriptLINQ
Carga masivamongoimport
Consulta AdhocNoNo
Almacenamiento
Fragmentación
DurabilidadServidor simple v1.8Diseño "crash-only"Escritura previa trazabilidad y aislamiento de instantáneas para garantizar recuperación vía ESE
TransaccionesNoNo
ConcurrenciaActualización in-placeMVCC (Multi-Version Concurrency Control)Concurrencia optimista
ConsistenciaMaestro fuerte / Esclavo eventualNodo fuerte / Cluster eventualEventual
ReplicaciónMaestro-Maestro con funciones de resolución personalizadasMaestro-EsclavoPlugin incluído
Interfaz
ProtocoloPersonalizado sobre TCP/IPHTTP/RESTHTTP/REST
.NET APIProyectos de tercerosProyectos de tercerosIncluído
Otros
TriggersNoValidación de actualización, Seguridad
SeguridadBásicaBásicaNinguna
Escrito enC++ErlangC#

Lenguajes de programación
La siguiente tabla muestra el uso de lenguajes de programación en varias bases de datos NoSQL. Yo hubiera añadido también Perl, C/C++, Erlang ó Go, que son lenguajes populares que también comprende MongoDB (entre otros muchos).

  BBDD Modo durabilidad java ruby python php .net http
documento mongodb basado en réplica x x x x x x
  couchdb nodo simple x x x x x x
  ravendb nodo simple - - - - x x
clave-valor redis en memoria, serializado en disco x x x x x -
  riak basado en réplica x x x x x x
tabular cassandra basado en réplica x x x x x -
grafo neo4j nodo simple x x x x - x
  sones nodo simple - - - - x x


Fuentes
http://nosql.mypopescu.com/post/1016366403/nosql-guide-for-beginners
http://nosql.mypopescu.com/post/978742866/document-databases-compared-couchdb-mongodb-ravendb

MongoDB: Ejemplo de configuración de fragmentación

Este post es una traducción del artículo original "Return to the Mongo Mailbag", de Kristina Chodorow.


En la lista de correo mongodb-user de la semana pasada, alguien preguntó (básicamente):

"Tengo 4 servidores y quiero dos frgamentos. ¿Cómo lo configuro?"

Mucha gente está preguntando sobre cómo configurar conjuntos de réplica y fragmentación, por lo que que aquí se explicará en detalle.


The Architecture

Prerequisitos. Si no estás familiarizado con los conjuntos de réplica, echa un vistazo a mi post en mi blog. El resto de este post no tendrá mucho sentido a menos que tú sepas qué es un árbitro. Además, deberías conocer los conceptos de la fragmentación.

Cada fragmento debería ser un conjunto de réplica, por lo que necesitaremos dos conjuntos de réplica (los llamaremos "foo" y "bar"). Queremos que nuestro cluster sea correcto si una de las máquinas se cae o se separa de la manada (partición de red), así que extenderemos fuera cada conjunto entre las máquinas disponibles. Los conjuntos de réplica están codificadas por color y las máquinas son nombradas imaginativamente server1-4.

Cada conjunto de replica tiene dos hosts y un árbitro. De esta manera, si un servidor se cae, ninguna funcionalidad se pierde (y ahí no estarán dos maestros en un servidor simple).

Para configurar ésto, ejecuta:

server1

$ mkdir -p ~/dbs/foo ~/dbs/bar
$ ./mongod --dbpath ~/dbs/foo --replSet foo
$ ./mongod --dbpath ~/dbs/bar --port 27019 --replSet bar --oplogSize 1


server2

$ mkdir -p ~/dbs/foo
$ ./mongod --dbpath ~/dbs/foo --replSet foo


server3

$ mkdir -p ~/dbs/foo ~/dbs/bar
$ ./mongod --dbpath ~/dbs/foo --port 27019 --replSet foo --oplogSize 1
$ ./mongod --dbpath ~/dbs/bar --replSet bar


server4

$ mkdir -p ~/dbs/bar
$ ./mongod --dbpath ~/dbs/bar --replSet bar


Los árbitros tienen un tamaño de oplog de 1. Por defecto, el tamaño de oplog es un ~5% de tu disco duro, pero los árbitros no necesitan mantener ningún dato, por lo que esto es un gran desperdicio de espacio.

Poner juntos los conjuntos de réplica

Ahora arrancaremos los dos conjuntos de réplica. Arrancar la consola mongo y escribir:

> db = connect("server1:27017/admin")
connecting to: server1:27017
admin
> rs.initiate({"_id" : "foo", "members" : [
... {"_id" : 0, "host" : "server1:27017"},
... {"_id" : 1, "host" : "server2:27017"},
... {"_id" : 2, "host" : "server3:27019", arbiterOnly : true}]})
{
  "info" : "Config now saved locally. Should come online in about a minute.",
  "ok" : 1
}
> db = connect("server3:27017/admin")
connecting to: server3:27017
admin
> rs.initiate({"_id" : "bar", "members" : [
... {"_id" : 0, "host" : "server3:27017"},
... {"_id" : 1, "host" : "server4:27017"},
... {"_id" : 2, "host" : "server1:27019", arbiterOnly : true}]})
{
  "info" : "Config now saved locally. Should come online in about a minute.",
  "ok" : 1
}


Ahora tenemos dos conjuntos de réplica en ejecución. Creemos ahora un cluster.


Configurar la fragmentación

Una vez intentemos configurar un sistema sin puntos simples de fallo, usaremos tres servidores de configuración. Podemos tener tantos procesos mongos como queramos (se recomienda uno en cada appserver), pero empezaremos con uno.

server2

$ mkdir ~/dbs/config
$ ./mongod --dbpath ~/dbs/config --port 20000


server3

$ mkdir ~/dbs/config
$ ./mongod --dbpath ~/dbs/config --port 20000


server4

$ mkdir ~/dbs/config
$ ./mongod --dbpath ~/dbs/config --port 20000
$ ./mongos --configdb server2:20000,server3:20000,server4:20000 --port 30000


Ahora añadiremos nuestros conjuntos de réplica al cluster. Concta los mongos y ejecuta el comando addshard:

> mongos = connect("server4:30000/admin")
connecting to: server4:30000
admin
> mongos.runCommand({addshard : "foo/server1:27017"})
{ "shardAdded" : "foo", "ok" : 1 }
> mongos.runCommand({addshard : "bar/server3:27017"})
{ "shardAdded" : "bar", "ok" : 1 }


Como puedes ver, terminarás con un fragmento "foo" y un fragmento "bar". (si estás usando una versión antigua de MongoDB, tus fragmentos tendrán nombres como “shard0000″ o “shard0001″)

Ahora puedes conectar a “server4:30000″ en tu aplicación y utilizarlo con un simple y “normal” mongod. Si quieres añadir más procesos mongos, simplemente arráncalos con los mismos parámetros configdb utilizados anteriormente.

MongoDB: Conjuntos de réplica. Parte 3

Este post asume que sabes qué son los conjuntos de réplica y algo de la sintáxis básica.

En la parte 1, configuramos un conjunto de réplica desde cero, pero la vida real es más desordenado: puedes querer migrar servidores de desarrollo a producción, añadir nuevos esclavos, priorizar servidores, cambiar cosas en el momento (on the fly)... y ésto es lo que este post cubre.


Antes de empezar…

A los conjuntos de réplica no les gusta localhost. Son serviciales para secundarlos... más o menos, bastante... pero a menudo provoca discrepancias. Puedes evitar estas discrepancias usando en su lugar el nombre del servidor (hostname). En Linux, puedes buscar tu nombre de servidor ejecutando el comando:

$ hostname
wooster


De aquí en adelante, usaremos mi nombre de servidor en lugar de localhost.


Arrancar con datos

Esto es más o menos que arrancar sin datos, escepto que deberías hacer una copia de seguridad de tus datos antes de arrancar (deberías siempre hacer un backup siempre de tus datos antes de hacer travesuras con tu servidor de configuración).

Si en el pre-conjunto-réplica, arrancaste tu servidor con algo como:

$ ./mongod

...conviértelo en el primer miembro de tu conjunto de réplica, por lo que has de parar y arrancar de nuevo con la opción –replset:

$ ./mongod --replSet unicomplex/wooster:27017

Ahora, inicializa el conjunto con el único servidor:

> rs.initiate()
{
"info" : "Config now saved locally. Should come online in about a minute.",
"ok" : 1
}



Agregar esclavos

Deberías arrancar MongoDB siempre con esclavos, así que agreguemos alguno.

Arranca tu servidor con las opciones usuales, así como también como –replSet. Así, por ejemplo, podríamos hacer:

$ ./mongod --dbpath ~/dbs/slave1 --port 27018 --replSet unicomplex/wooster:27017

Ahora, agregamos este esclavo al conjunto de réplica. Asegurarse de que db está conectado a wooster:27017 (el servidor primario) y arrancar:

> rs.add("wooster:27018")
{"ok" : 1}


Repetir como sea necesario para agregar más esclavos.


Agregar un árbitro

Esto es muy similar a agregar un esclavo. Cuando arranques el árbitro, deberías darle la opción –oplogSize 1. De esta manera el árbitro no desperdiciará espacio.

$ ./mongod --dbpath ~/dbs/arbiter --port 27019 --replSet unicomplex/wooster:27017 --oplogSize 1

Ahora agregarlo al conjunto. Puedes especificar que este servidor es un árbitro pasando en un objeto un campo arbiterOnly a rs.add:

> rs.add({"host" : "wooster:27019", "arbiterOnly" : true})
{"ok" : 1}



Degradar un primario

Supongamos que nuestra compañía tiene disponibles los siguientes servidores:

1. Super máquina Gazillion dollar
2. Instancia EC2
3. iMac que encontramos en la calle

A través de un accidente del destino, el iMac se convierte en primario. Podemos forzarle a que se convierta en esclavo ejecutando el comando:

> imac = connect("imac.example.com/admin")
connecting to: imac.example.com/admin
admin
> imac.runCommand({"replSetStepDown" : 1})
{"ok" : 1}


Ahora el iMac será un esclavo.


Establecer prioridades

Podemos indicar que el iMac nunca sea un maestro (queremos usarlo sólo como backup). Puedes forzar ésto estableciendo su prioridad a cero. La más alta prioridad de un servidor es la que hará que se convierta en maestro si el actual maestro falla. Las únicas opciones son 0 (no puede ser maestro) o 1 (puede ser maestro), pero en el futuro serás capaz de tener una buena graduación de prioridades..

Así, cambiaremos la prioridad del iMac a 0. Para cambiar la configuración, conectemos al maestro y editemos su configuración:

> config = rs.conf()
{
"_id" : "unicomplex",
"version" : 1,
"members" : [
{
"_id" : 0,
"host" : "prod.example.com:27017"
},
{
"_id" : 1,
"host" : "ec2.example.com:27017"
},
{
"_id" : 2,
"host" : "imac.example.com:27017"
}
]
}


Ahora, tenemos que hacer dos cosas: 1) establecer la prioridad del iMac a 0, y 2) actualizar la versión de la configuración. El nuevo número de versión es siempre el anterior más uno

> config.members[2].priority = 0
0
> config.version += 1
2


Finalmente, decimos al conjunto de réplica que tenemos una nueva configuración.

> use admin
switched to db admin
> db.runCommand({"replSetReconfig" : config})
{"ok" : 1}


Todos los cambios de configuración deben ocurrir en el maestro. Éstos se propagarán de éste a los esclavos. Ahora puedes "matar" cualquier servidor y el iMac nunca se convertirá en maestro.

Esta configuración es un poco melindrosa para hacer desde la consola. En el futuro, la gente probablemente utilice una GUI para configurar sus conjuntos y trastear con la configuración del servidor.


Artículo original: http://www.snailinaturtleneck.com/blog/2010/08/03/part-3-replica-sets-in-the-wild/