martes, 11 de mayo de 2010

Primeros pasos en Java y MongoDB - Parte 1

MongoDB es una base de datos que cuenta con una amplia comunidad, y fruto de ello, son los proyectos que en torno ella se generan, especialmente los drivers, los cuales permiten acceder a la base de datos desde cualquier lenguaje de programación. En este post se realizará una introducción al uso del Driver de Java para Mongo.

Nota:
Se asume que el lector tiene conocimientos sobre programación de Java. En este artículo se omite cualquier estructura de código Java, enfocándose únicamente en las declaraciones y usos concretos del driver de Java para MongoDB.


Descarga del driver de Java

El Driver de Java para Mongo se encuentra en la siguiente URL:

http://www.mongodb.org/display/DOCSES/Centro+de+lenguaje+Java


Documentación sobre el driver

El Driver de Java cuenta con una documentación muy completa, la cual es accesible desde la siguiente URL:

http://www.mongodb.org/display/DOCSES/Centro+de+lenguaje+Java


Conexión al servidor

El primer paso a realizar es importar las clases del driver. Para ello, utilizar la sentencia import de la siguiente manera:

import com.mongodb.*;

Una vez importadas las clases, lo primero es crear una conexión al servidor. Existen varias maneras de hacer ésto:

// Conexion por defecto a localhost por el puerto 27017
Mongo con = new Mongo();
// Conexion al servidor "mongosrv" por el puerto 27017
Mongo con = new Mongo("mongosrv");
// Conexion al servidor "mongosrv" por el puerto 30000
Mongo con = new Mongo("mongosrv", 30000);



Uso de una base de datos

Un servidor de base de datos MongoDB puede tener múltiples bases de datos. Para indicar qué base de datos se desea utilizar, introducir la siguiente sentencia:

DB bbdd = con.getDB("nombreBaseDatos");


Utilizar una colección

Una vez en uso la base de datos, hay que especificar qué colección de entre las existentes en dicha base de datos, queremos utilizar. Para ello, se obtiene la colección a través de la siguiente sentencia:

DBCollection col = bbdd.getCollection("nombreColeccion");


Consultas simples

La consulta más sencilla posible sería la siguiente:

DBObject doc = col.findOne();
System.out.println(doc);


Retornaría el primer documento de la colección, mostrándolo por la consola.

Para obtener más documentos, hay que recuperar un cursor:

DBCursor cur = col.find();
while (cur.hasNext())
  System.out.println(cur.next());


El código anterior recuperaría todos los documentos de la colección y los mostraría por la consola.


Consultas de filtro

Las consultas de filtro permiten seleccionar solamente aquellos documentos que cumplen algún criterio. Por ejemplo, imaginemos que tenemos una colección Agenda, y queremos consultar todos los contactos de Madrid. La consulta sería la siguiente:

...
DBCollection col = bbdd.getCollection("Agenda");

// Se crea el documento de filtro
BasicDBObject filtro = new BasicDBObject();
filtro.put("provincia", "Madrid");
DBCursor cur = col.find(filtro);
while (cur.hasNext())
  System.out.println(cur.next());


Esta consulta sería similar a si lo hiciéramos desde la consola mongo:

db.Agenda.find({"provincia":"Madrid"})

Para ser más concretos y precisos en el filtro, se pueden añadir más condiciones, con las cuales se realizaría una selección AND/Y. Por ejemplo, para extraer los documentos de aquellas personas que se llamen Pedro, Y que vivan en Madrid, Y que tengan vehículo, el filtro quedaría de la siguiente manera:

filtro.put("nombre", "Pedro");
filtro.put("provincia", "Madrid");
filtro.put("vehiculo", true);


Esto equivaldría a:

db.Agenda.find({"nombre":"Madrid", "provincia":"Madrid", "vehiculo":true})

También es posible especificar operadores lógicos para limitar el rango de la consulta. El siguiente ejemplo extaería de la agenda a las personas mayores de edad que pueden trabajar:

filtro.put("edad", new BasicDBObject("$gte", 18));
filtro.put("edad", new BasicDBObject("$lte", 65));


Esto equivaldría a:

db.Agenda.find({"edad":{"$gte":18}, "edad":{"$lte":18}})

Nota: Para más información sobre consultas avanzadas mediante el uso de operadores lógicos, consultar: Consultas Avanzadas o Complejas


Acceso a los valores

Las aplicaciones que acceden a los datos, normalmente lo harán a sus valores, con el fin de realizar operaciones concretas con los mismos: formato, cálculo, comparación, etc.

El siguiente ejemplo valida un usuario y una contraseña, recogiendo el nombre completo, el idioma y la edad:

...
DBCollection col = bbdd.getCollection("Usuarios");

String sUsuario = "usuario";
String sPassword = "password";
String sNombre;
String sIdioma;
Integer iEdad;

BasicDBObject filtro = new BasicDBObject();
filtro.put("usuario", sUsuario);
filtro.put("password", sPassword);
DBObject result = col.findOne(filtro);

if (result==null)
  System.out.println("No se encuentra el usuario");
else {
  sNombre = (String)result.get("nombre");
  sIdioma = (String)result.get("idioma");
  sEdad = (Integer)result.get("edad");
}


Imaginemos ahora que deseamos recoger todas las áreas donde un determinado usuario puede acceder. La estructura de su documento podría ser el siguiente:

{"usuario":"usuario", "areas":["Area 1", "Area 2", "Area 3"]}

En este caso, la clave areas es un array. Para poder leer este array y almacenarlo en un vector interno, se utilizaría el siguiente código:

...
DBCollection col = bbdd.getCollection("Usuarios");

Vector v;

BasicDBObject filtro = new BasicDBObject();
filtro.put("usuario", "usuario");
DBObject result = col.findOne(filtro);

if (result==null)
  System.out.println("No se encuentra el usuario");
else {
  v = new Vector();
  BasicDBList dbl = (BasicDBList)obj.get("areas");
  for (int i=0; i<dbl.size(); i++)
    v.add((String)dbl.get(i));
}


Imaginemos ahora documentos en un array embebido en otro documento:

{"usuario":"usuario", prestado:[{"tipo":"libro", "titulo":"Don Quijote"}, {"tipo":"pelicula", "titulo":"Casablanca"}]}

El acceso a este esquema sería el siguiente:

...
DBCollection col = bbdd.getCollection("Usuarios");

BasicDBObject filtro = new BasicDBObject();
filtro.put("usuario", "usuario");
DBObject result = col.findOne(filtro);

if (result==null)
  System.out.println("No se encuentra el usuario");
else {
  BasicDBList dbl = (BasicDBList)obj.get("prestado");
  for (int i=0; i<dbl.size(); i++) {
    DBObject doc = dbl.get(i);
    System.out.println("Tipo: "+ (String)doc.get("tipo") + " / Titulo: " + (String)doc.get("titulo"));
  }
}