Acceso a Datos

2º DAM - Curso 2020-2021

User Tools

Site Tools


apuntes:mongodb

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:

  • En Windows
c:\Users\Santi\> mongod --dbpath=ruta_base_de_datos
  • En Linux/OSX
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):

  • En Windows
c:\Users\Santi\> mongo --host 192.168.100.23 --port 27017 -u usuario -p password
  • En Linux/OSX
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:

  • Ver las bases de datos existentes
> show dbs
biblioteca   0.203GB
ejemplo      0.203GB
local        0.078GB
  • Conectar/Crear una base de datos
> use biblioteca
switched to db biblioteca
  • Ver las colecciones dentro de una base de datos
> show collections
libros
system.indexes
  • Eliminar una base de datos
> db.dropDatabase()
{ "dropped" : "biblioteca", "ok" : 1 }
  • Mostrar ayuda
> 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

  • db.collection.insert()
  • db.collection.insertOne()
  • db.collection.insertMany()

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

  • db.collection.find()

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

  • db.collection.update()
  • db.collection.updateOne()
  • db.collection.updateMany()
  • db.collection.replaceOne()

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

  • db.collection.remove()
  • db.collection.deleteOne()
  • db.collection.deleteMany()

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.

  • find(eq(“titulo”, “Secuestrado”)) - Buscará todos los documentos que tengan como titulo el valor 'Secuestrado'. También se puede utilizar para buscar valores dentro de un array en el documento de una colección
  • find(gt(“paginas”, 50)) - Buscará todos los documentos que tengan más de 50 páginas
  • find(gte(“paginas”, 50)) - Buscará todos los documentos que tengan 50 o más páginas
  • find(and(gte(“paginas”, 50), lte(“paginas”, 75)) - Buscará todos los documentos que tengan entre 50 y 100 páginas (ambos valores incluidos)
  • find(or(eq(“genero”, “novela”), eq(“genero”, “accion”)) - Buscará todos los documentos que sean del género 'novela' y 'accion'

Ejemplos

  • Devuelve el primer documento que coincida con el campo y valor especificados:
Document documento = db.getCollection("libros").find(eq("titulo", "Secuestrado")).first();
  • Devuelve todos los documentos que coincidan con el campo y valor especificados:
FindIterable iterable = db.getCollection("libros").find(eq("titulo", "Secuestrado"));
  • Devuelve los primeros diez documentos que coincidan con el campo y valor especificados:
FindIterable iterable = db.getCollection("libros").find(eq("titulo", "Secuestrado")).limit(10);
  • Devuelve los documentos encontrados saltándose los diez primeros:
FindIterable iterable = db.getCollection("libros").find(eq("titulo", "Secuestrado")).skip(10);
  • Busca en un documento que tiene otro embebido:
FindIterable iterable = db.getCollection("libros").find(eq("editorial.nombre", "Anaya"));
  • Búsqueda sobre dos campos (género y número de páginas). Busca los libros de género Novela que tengan más de 100 páginas.
FindIterable iterable = db.getCollection("libros").find(and(eq("genero", "Novela"), gt("paginas", 100));

Operadores

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

  • Operadores de comparación: eq, gt, gte, lt, lte, ne, in, nin
  • Operadores lógicos: or, and, not
Se pueden encontrar más ejemplos de métodos para realizar búsquedas en el Tutorial de MongoDB para Java

Proyectos de ejemplo

Todos los proyectos de ejemplo de esta parte están en el repositorio java-mongodb 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 sección Referencias

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)

  • La Base de Datos contendrá, al menos, 2 colecciones relacionadas entre ellas.
  • Se podrá llevar a cabo el alta de documentos.
  • Se podrá llevar a cabo la modificación de documentos.
  • Se podrá llevar a cabo la baja de documentos.
  • Se podrán llevar a cabo búsquedas simples (por un campo) y complejas (utilizando condiciones para más de un campo).

Otras funcionalidades (1 pto cada una)

  • Ampliar la base de datos a 4 colecciones.
  • Utilizar alguna colección que contenga estructuras complejas (arrays, datos estructurados, . . .).
  • Implementar un mecanismo de usuario/contraseña.
  • Implementar una barra de estado donde mostrar un resumen de los datos que visualiza el usuario en cada momento (qué datos, cuantos objetos, qué objeto tiene seleccionado actualmente y los mensajes oportunos según la acción que realice).
  • La aplicación refrescará los datos mostrados de forma automática antes posibles cambios en la base de datos.
  • Permitir importar datos desde una base de datos relacional (MySQL, por ejemplo) a alguna colección de la aplicación.
  • Permitir exportar datos a alguna tabla de una base de datos relacional (MySQL, por ejemplo).
  • Permitir exportar datos de colecciones como ficheros CSV.
  • Permitir importar datos de colecciones desde un fichero CSV.

© 2016-2019 Santiago Faci

2)
FindIterable es una colección iterable para recorrer los documentos encontrados
apuntes/mongodb.txt · Last modified: 25/11/2019 18:38 by Santiago Faci