Table of Contents

Acceso a Bases de Datos NoSQL. MongoDB

¿Qué es MongoDB

MongoDB es una base de datos orientada a documentos, clasificada como un SGBD NoSQL. Utiliza documentos JSON para crear el esquema de la base de datos.

Estructura de una Base de Datos

Como se ha comentado, MongoDB almacena la información y forma el esquema de la base de datos mediante el uso de documentos JSON, tal y como se muestra en la siguiente figura:

Figure 1: Documento JSON en MongoDB

Así, el esquema en MongoDB es totalmente flexible puesto que no obliga a diseñar un esquema o modelo antes de poder comenzar a registrar información. De esa forma es mucho más fácil hacer mapear los documentos con objetos en nuestra aplicación, puesto que es fácil adaptarnos a los cambios que estos últimos puedan sufrir

Puesta en marcha de MongoDB

Una vez descargado MongoDB, para ponerlo en marcha, tendremos que crear la ruta donde queremos que se almacenen nuestras bases de datos. Y a continuación, lanzar el servidor ejecutando el siguiente comando:

Hay que tener en cuenta que, por defecto, MongoDB escuchará en el puerto 27017:

c:\Users\Santi\> mongod --dbpath=ruta_base_de_datos
santi@zenbook:$ ./mongod --dbpath=ruta_base_de_datos

Además, MongoDB dispone de una consola cliente que podemos lanzar ejecutando el comando mongo, que intentará conectar directamente con un servidor ubicado en el propio equipo y con el puerto por defecto, el 27017. También podemos especificar esos parámetros desde la línea de comandos al ejecutarlo (junto con usuario y contraseña si fuera necesario también):

c:\Users\Santi\> mongo --host 192.168.100.23 --port 27017 -u usuario -p password
santi@zenbook:$ ./mongo --host 192.168.100.23 --port 27017 -u usuario -p password

Una vez ejecutado entraremos en la consola de MongoDB donde, entre otros, tenemos los siguientes comandos disponibles:

> show dbs
biblioteca   0.203GB
ejemplo      0.203GB
local        0.078GB
> use biblioteca
switched to db biblioteca
> show collections
libros
system.indexes
> db.dropDatabase()
{ "dropped" : "biblioteca", "ok" : 1 }
> help
	db.help()                    help on db methods
	db.mycoll.help()             help on collection methods
	sh.help()                    sharding helpers
	rs.help()                    replica set helpers
	help admin                   administrative help
	help connect                 connecting to a db help
. . .
. . .



Conectar con MongoDB

Para empezar a trabajar con MongoDB desde Java, primero tendremos que hacernos con el Driver. Podéis encontrar su enlace de descargar en la sección Software Necesario de los apuntes.

Conectar con la Base de Datos MongoDB desde Java

MongoClient mongoClient = new MongoClient();
MongoDatabase db = mongoClient.getDatabase("basededatos");

Desconectar de la Base de Datos

mongoClient.close()

Hay que tener en cuenta que para poder conectarnos con MongoDB primero tendremos que arrancar el servidor de la forma que se indica un poco más arriba en la puesta en marcha.

Utilizar CodecRegistry para mapear POJOs a Documentos

También podemos, si hemos creado un CodecRegistry a la hora de conectar con MongoDB, trabajar directamente con los POJO para insertar, modificar o leer documentos en la base de datos:

. . .
CodecRegistry pojoCodecRegistry = CodecRegistries.fromRegistries(MongoClient.getDefaultCodecRegistry(),
    CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build()));
MongoClient cliente = new MongoClient("localhost", 
    MongoClientOptions.builder().codecRegistry(pojoCodecRegistry).build());
MongoDatabase db = cliente.getDatabase(NOMBRE_BASEDATOS);
. . .

A través del CodecRegistry los objetos Java se mapearán automáticamente como documentos a la hora de insertarlos y modificarlos en la colección correspondiente, y también serán mapeados automáticamente a objetos Java desde la colección MongoDB cuando hagamos una lectura.

Más adelante, en los ejemplos de operaciones básicas de inserción, modificación y lectura, se muestran ejemplos de cómo realizar esas operaciones también en el caso de que se haya optado por instanciar y asociar a nuestra conexión un CodecRegistry.

Operaciones básicas

MongoDB proporciona varias vías para ejecutar cada una de las operaciones CRUD 1) (Create, Read, Update, Delete) que podemos realizar en todo SGBD.

Operaciones de creación

Ejemplo desde línea de comandos

db.libros.insert(                     // colección
  {                                   // documento
    titulo: "Secuestrado",
    descripcion: "Las aventuras de David Balfour",
    autor: "Robert Louis Stevenson",
    fecha: "2/5/2002",
    disponible: "true"
  }
)

Ejemplo desde Java

Document documento = new Document()
         .append("titulo", libro.getTitulo())
         .append("descripcion", libro.getDescripcion())
         .append("autor", libro.getAutor())
         .append("fecha", libro.getFecha())
         .append("disponible", libro.getDisponible()));
db.getCollection("libros").insertOne(documento);

Si hemos instanciado un CodecRegistry con nuestra conexión a MongoDB (como se explica en el apartado de Conectar con MongoDB), suponiendo que tenemos un objeto coche de la clase Coche que queremos insertar como documento en una colección MongoDB, podríamos hacer lo siguiente:

MongoCollection<Coche> coleccionCoches = db.getCollection("coches", Coche.class);
coleccionCoches.insertOne(coche);

Operaciones de lectura

Ejemplo desde consola

db.usuarios.find(                                   // colección
  {autor: {$eq: "Robert Louis Stevenson"}},         // criterio
  {titulo: 1, descripcion: 1}                       // projección
).limit(10)                                         // modificador del cursor

Ejemplo desde Java 2)

Document documento = new Document("autor", "Robert Louis Stevenson");
FindIterable findIterable = db.getCollection("libros")
                .find(documento)
                .limit(10);
 
List<Libro> libros = new ArrayList<Libro>();
Libro libro = null;
Iterator<Document> iter = findIterable.iterator();
while (iter.hasNext()) {
  Document documento = iter.next();
  libro = new Libro();
  libro.setId(documento.getObjectId("_id"));
  libro.setTitulo(documento.getString("titulo"));
  libro.setDescripcion(documento.getString("descripcion"));
  libro.setAutor(documento.getString("autor"));
  libro.setFecha(documento.getDate("fecha"));
  libro.setDisponible(documento.getBoolean("disponible", false));
  libros.add(libro);
}

Utilizando CodecRegistry (como se explica en el apartado de Conectar con MongoDB) para mapear automáticamente los POJO como documentos de una colección de MongoDB, también podemos leer:

. . .
MongoCollection<Coche> coleccionCoches = db.getCollection("coches", Coche.class);
List<Coche> coches = coleccionCoches.find().into(new ArrayList<Coche>());
. . .

De esa manera obtenemos, mapeando automáticamente a través del CodecRegistry, una colección de objetos Coche casi directamente de una colección MongoDB.

Operaciones de modificacion

Ejemplo desde consola

db.usuarios.update(                              // colección
  { titulo: { $eq: "Secuestrado"}},              // criterio
  { $set: {autor: "Robert Louis Stevenson"}}      // modificación
)

Ejemplos desde Java

// Modifica un campo específico de un documento
db.getCollection("libros").updateOne(new Document("titulo", "Secuestrado"),
         new Document("$set", new Document("autor", "Robert Louis Stevenson"));
 
// Reemplaza un documento completo
db.getCollection("libros").replaceOne(new Document("_id", libro.getId()),
         new Document()
         .append("titulo", libro.getTitulo())
         .append("descripcion", libro.getDescripcion())
         .append("autor", libro.getAutor())
         .append("fecha", libro.getFecha())
         .append("disponible", libro.getDisponible()));

De nuevo, utilizando CodecRegistry (como se explica en el apartado de Conectar con MongoDB) para el mapeo automático de los documentos en objetos Java (POJO), podemos modificar un documento de MongoDB pasándole directamente el objeto Java. En el ejemplo siguiente, tenemos el objeto con todos los campos ya modificados (excepto el id, que nunca tocaremos) y, utilizando el id como filtro, pasamos el objeto que será mapeado al documento que reemplazará al que haya actualmente en la base de datos:

. . .
MongoCollection<Coche> coleccionCoches = db.getCollection("coches", Coche.class);
coleccionCoches.replaceOne(eq("_id", coche.get_id()), coche);
. . .

Operaciones de borrado

Ejemplo desde consola

db.usuarios.remove(                   // colección
  { poblacion: "Zaragoza"}            // criterio
)

Ejemplo desde Java:

db.getCollection("libros").deleteOne(new Document("titulo", titulo));

También podemos hacerlo directamente sobre la colección, utilizando de nuevo un CodeRegistry (como se explica en el apartado de Conectar con MongoDB). En el ejemplo siguiente, tenemos el objeto cuyo documento queremos eliminar de la base de datos, y utilizamos el id como filtro para localizarlo y borrarlo de la colección:

. . .
MongoCollection<Coche> coleccionCoches = db.getCollection("coches", Coche.class);
coleccionCoches.deleteOne(eq("_id", coche.get_id()));
. . .

Búsquedas

En este apartado vamos a ver diferentes formas de realizar búsqueda de documento sobre una Base de Datos MongoDB.

Para realizar búsquedas se utiliza el método find(), que sería el equivalente a SELECT que utilizamos en el lenguaje SQL en Bases de Datos Relacionales. A ese método le podemos pasar un documento que haga de patrón para buscar en la colección todos aquellos que coincidan con él, como se puede ver en el ejemplo que se ha hecho anteriormente. Pero también se pueden pasar una serie de métodos que permiten establecer condiciones muy al estilo de las que se pasaban en las clausulas WHERE de las sentencias SQL.

Ejemplos

Document documento = db.getCollection("libros").find(eq("titulo", "Secuestrado")).first();
FindIterable iterable = db.getCollection("libros").find(eq("titulo", "Secuestrado"));
FindIterable iterable = db.getCollection("libros").find(eq("titulo", "Secuestrado")).limit(10);
FindIterable iterable = db.getCollection("libros").find(eq("titulo", "Secuestrado")).skip(10);
FindIterable iterable = db.getCollection("libros").find(eq("editorial.nombre", "Anaya"));
FindIterable iterable = db.getCollection("libros").find(and(eq("genero", "Novela"), gt("paginas", 100));

Operadores

A continuación, los operadores más habituales:

Se pueden encontrar más ejemplos de métodos para realizar búsquedas en el Tutorial de MongoDB para Java

Ejercicios Examen

  1. Crea una base de datos en MongoDB con tu nombre y crea una colección de juegos, almacenando la siguiente información sobre cada uno: título, género, precio y fecha de lanzamiento
    1. Inserta un juego rellenando todos los campos
    2. Inserta un juego sin indicar fecha de lanzamiento
    3. Realiza una búsqueda de todos los juegos del mismo género y ordénalos por título
    4. Crea una aplicación Java que permita conectar con la base de datos que has creado de forma que se pueda listar, en una tabla, la información de los dos juegos introducidos
    5. Añade a la aplicación la posibilidad de registrar nuevos juegos, considerando el título como campo obligatorio
    6. Añade a la funcionalidad de registrar nuevos juegos un control para que no sea posible registrar dos juegos con el mismo nombre. En ese caso se mostrará un mensaje de error al usuario y tendrá que proporcionar otro nombre diferente
    7. Añade una nueva funcionalidad que permita eliminar todos los juegos de un mismo género. Prepara un combo que liste los géneros y el usuario, seleccionando uno de ellos, podrá eliminar todos los juegos que pertenezcan al mismo
    8. Añade una funcionalidad que permita modificar los datos de un juego

Proyectos de ejemplo

Todos los proyectos de ejemplo de esta parte están en el repositorio java-mongodb y en el repositorio de JavaFX de GitHub.

Los proyectos que se vayan haciendo en clase estarán disponibles en el repositorio datos-ejercicios, también en GitHub.

Para manejaros con Git recordad que tenéis una serie de videotutoriales en La Wiki de Git


Práctica 4.1

Objetivos

Desarrollar una aplicación con una base de datos NoSQL (MongoDB)

Enunciado

Siguiendo el mismo diseño de la aplicación de las práctica 1.1, 2.1 y 3.1, se deberá implementar una aplicación que conecte con una base de datos NoSQL (MongoDB), según los requisitos que se enumeran a continuación

Requisitos (1 pto cada uno)

Otras funcionalidades (1 pto cada una)


© 2016-2019 Santiago Faci

2)
FindIterable es una colección iterable para recorrer los documentos encontrados