Herramientas de usuario

Herramientas del sitio


apuntes:mongodb

Acceso a Bases de Datos NoSQL. MongoDB

Introducción a las Bases de Datos NoSQL

Con el potente crecimiento de las redes sociales, se ha necesitado dar respuestas rápidas a una cantidad elevada de clientes, con peticiones de enormes colecciones de datos.

Viendo que los tradicionales SGBD Relacionales emplean demasiado tiempo en controlar la consistencia de los datos (relaciones, restricciones), se necesita un mayor rendimiento a la hora de obtener muchos datos en tiempo real. De estas necesidades surgen las bases de datos NoSQL (Not Only SQL).

Se caracterizan por no emplear SQL como lenguaje principal de consulta. Existen diferentes tipos de bbdd NoSql:

  • bbdd clave-valor
  • bbdd de Documentos
  • bbdd orientadas a objetos
  • bbdd en grafo

MongoDB

¿Qué es MongoDB?

MongoDB es un sistema gestor de bases de datos NoSQL de código abierto, orientado a documentos. Utiliza documentos basados en JSON (JavaScript Object Notation) para almacenar informacion en la base de datos.

La principal diferencia con los tradicionales sistemas relacionales, es la flexibilidad a la hora de modificar la estructura de los datos almacenados. Los documentos almacenados en una base de datos (colección) pueden tener diferentes campos.

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 BSON (Binary JSON). Los ficheros JSON son relaciones clave-valor y tienen el siguiente aspecto:

Estructura Documento BSON

Así, el esquema en MongoDB es totalmente flexible puesto que depende solamente del documento insertado, pudiendo tener cada documento distinta cantidad de campos. De esa forma es mucho más fácil mapear los documentos con objetos en nuestra aplicación, puesto que es fácil adaptarnos a los cambios que estos últimos puedan sufrir.

SGBD Relacional MongoDB
Base de Datos Base de Datos
TablaColección
Fila o RegistroDocumento
Relación Sub-documento integrado (Enbedded) o referenciado

Documentos BSON

BSON es una representación binaria de documentos tipo JSON. Permite integrar sub-documentos así como el uso de arrays, pero también permite representar tipos de datos a diferencia de JSON.

Estos documentos de texto son ligeros y utilizan una cláve única por cada documento (campo _id). Cada documento está formado por campos únicos (claves) a los que se les da un valor, lo que permite la recuperación de la información de forma muy rápida.

Campo _id

En MongoDB, cada documento almacenado en una colección requiere un identificador único que actúa de forma similar a una clave primaria. Si se omite este campo en un documento insertado en una colección, MongoDB genera automáticamente un valor ObjectId para el campo _id.

El tipo de datos ObjectID de los documentos BSON es un valor de 12 bytes único, fácil y rápido de generar, y está ordenado.

Puesta en marcha de MongoDB

Una vez descargado el servidor MongoDB Server, 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\Fer\> mongod --dbpath=ruta_base_de_datos
  • En Linux/OSX
fer@zenbook:$ ./mongod --dbpath=ruta_base_de_datos

Si no queremos especificar una ruta propia donde guardar las bases de datos, por defecto en Windows se guardarán en “C:\data\db\”. Debemos crear al menos dicho directorio.

Para ejecutar el servidor de forma fácil, en Windows podemos hacer un acceso directo en el escritorio del programa mongod.exe, indicándole en las propiedades del accesso directo la ruta de destino con las opciones necesarias. Por ejemplo si mi directorio de bases de datos esta en “C:\users\Fer\mongodb\data\db” indicaré en las propiedades: “C:\Program Files\MongoDB\Server\3.6\bin\mongod.exe” –dbpath C:\users\Fer\mongodb\data\db

MongoDB también incluye su propio cliente GUI para administrar las bases de datos. Se llama MongoDB Compass y se incluye con el paquete de instalación de Mongo DB:

Además, MongoDB también 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\Fer\> mongo --host 192.168.100.23 --port 27017 -u usuario -p password
  • En Linux/OSX
fer@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
. . .
. . .


Java MongoDB Driver

Para empezar a trabajar con MongoDB desde Java, primero tendremos que hacernos con el Driver. Los drivers son librerías JAR que se deben añadir a nuestro proyecto. Se pueden descargar desde la sección de drivers Java para MongoDB. Para conectar con MongoDB necesitamos lo siguiente:

  • mongo-driver.jar : Driver de Java para conectar con MongoDB. Tiene dos dependencias:
  • bson.jar: Librerías de documentos BSON que usa MongoDB
  • mongo-driver-core.jar: Driver de MongoDB para operaciones de bajo nivel

En la sección de descargas también se incluye una librería llamada Uber MongoDB Java Driver que incluye las librerías descritas anteriormente:

  • mongo-java-driver.jar: Driver de Java, que contiene sus dependencias.

Conexion con MongoDB

Creamos un objeto MongoClient, que representa un pool de conexiones con el servidor de MongoDB. Con el crearemos una conexión a una base de datos mediante el objeto MongoDatabase:

MongoClient mongoClient = new MongoClient();
//O si quiero abrir conexiones con un servidor remoto
MongoClient mongoClient = new MongoClient( "localhost" , 27017 );
 
//Establecer conexión con una base de datos
MongoDatabase db = mongoClient.getDatabase("baseDatos");
 
//Y si queremos trabajar directamente con una coleccion concreta
MongoCollection coleccion = db.getCollection("coleccion"); 

Si la base de datos o la coleccion no existen, se crearán de forma automática.

Desconectar de la Base de Datos

Debemos asegurarnos de cerrar los recursos abiertos con el servidor

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 sección Puesta en marcha.

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.

En java los documentos que utilizamos en estas operaciones pueden estar representados por objetos de la clase org.bson.Document.

Operaciones de inserción

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

Ejemplo desde línea de comandos

db.libros.insertOne(                  // 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);
 
// Podemos insertar también varios documentos almacenados en una lista
List<Document> listaLibros = new ArrayList<Document>();
...
db.getCollection("libros").insertMany(listaLibros);
 
//Vemos cuántos documentos hay en la colección
System.out.println(db.getCollection("libros").count());

Operaciones de modificacion

  • db.collection.replaceOne(): Sustituir un documento completo
  • db.collection.updateOne() : Actualizar campos en un documento
  • db.collection.updateMany(): Actualizar campos en varios documento

Ejemplo desde consola

db.usuarios.updateOne(                           // 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()));

Operaciones de borrado

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

Ejemplo desde consola

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

Ejemplo desde Java:

//Para borrar un solo documento debemos utilizar un valor para un campo único (_id)
db.getCollection("libros").deleteOne(new Document("_id", "345367"));
 
db.getCollection("libros").deleteMany(new Document("autor", "Reverte"));

Operaciones de consulta

  • db.collection.find()

Ejemplo desde consola

db.usuarios.find(                                   // colección
  {autor: {$eq: "Robert Louis Stevenson"}},         // criterio
  {titulo: 1, descripcion: 1})                      // proyección 

Ejemplo desde Java El método find() devuelve una colección FindIterable, que se puede recorrer con un Iterator.

//Buscar el primer documento
Document libro = db.getCollection("libros").find().first();
 
//Buscar todos los documentos 
FindIterable findIterable = db.getCollection("libros").find();
 
//Buscar un libro concreto: titulo = "Secuestrado"
Document documento = new Document("titulo", "Secuestrado");
Document libro = db.getCollection("libros").find(documento).first();
//O también
Document libro = db.getCollection("libros").find({titulo: "Secuestrado"}).first();
 
//Buscar todos los libros de un autor concreto
Document documento = new Document("autor", "Robert Louis Stevenson");
FindIterable findIterable = db.getCollection("libros").find(documento);
 
//Recorrer el conjunto de resultados
Iterator<Document> iter = findIterable.iterator();
 
List<Libro> libros = new ArrayList<Libro>();
Libro libro = null;
 
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);
}

Operaciones de consulta avanzada

Podemos establecer distintos criterios de busqueda

En la documentación de mondoDB tenemos un tutorial con más ejemplos de operaciones

Relaciones entre documentos

Las relaciones en MongoDB se gestionan de forma diferente a los sistemas de bases de datos relaciones. En MongoDB tenemos más flexibilidad ya que, como hemos visto, no hay que definir una estructura fija para los campos de un documento.

En MongoDB existen dos planteamientos a la hora de realizar las relaciones, y se aplicará uno u otro dependiendo de qué relación guarden los distintos documentos:

  • Patrón Enbedding: un documento contiene sub-documentos integrados
  • Patrón Referencing: un documento contiene los id's integrados de otros documentos

Para ver los siguientes ejemplos vamos a plantear dos tipos de documentos: empleados, que almacena información sobre los empleados, y departamentos que almacena datos sobre la dirección de los departamentos.

Relaciones Enbedding

Este patrón se usa cuando necesitamos acceder a los empleados y ver también sus departamentos relacionados. Favorece la consulta de los documentos de empleados, pero no permite acceder directamente a los documentos de sus departamentos relacionados.

Relaciones 1 a 1

En el documento de un empleado, integramos el documento de su departamento:

{
   _id: ObjectID("AAAA"),
   nombre: "Joe",
   apellidos: "Book Reader"
   departamento: {
              calle: "123 Fake Street",
              ciudad: "Faketon",
              provincia: "MA",
              cp: "12345"
            }
}

Relaciones 1 a N (pocos)

Cuando cada empleado se relaciona con unos pocos departamentos, podemos usar un array que integre los departamentos relacionados.

{
   _id: ObjectID("AAAA"),
   nombre: "Joe",
   apellidos: "Book Reader"
   departamentos: [
                {
                  calle: "123 Fake Street",
                  ciudad: "Faketon",
                  provincia: "MA",
                  cp: "12345"
                },
                {
                  calle: "1 Other Street",
                  ciudad: "Boston",
                  provincia: "CA",
                  cp: "56789"
                }
              ]
 }

Relaciones Referencing

Consisten en almacenar en un documento un campo con el valor del _id de otro o varios documentos. Se utiliza cuando queremos acceder de forma directa a los empleados, pero tambien directamente a los departamentos con los que se relaciona.

Relaciones 1 a N (varios)

//Documento empleado, guarda las referencias a varios departamentos
{
   _id: ObjectID("AAAA"),
   nombre: "Joe",
   apellidos: "Book Reader"
   departamentos: [ ObjectID("ABCD"), ObjectID("EFGH"), ObjectID("JKLM")]   
}
 
//Documentos de Departamentos
{
   _id: ObjectId("ABCD")
   calle: "123 Fake Street",
   ciudad: "Faketon",
   provincia: "MA",
   cp: "12345"
}
 
{
   _id: ObjectId("EFGH")
   calle: "1 Other Street",
   ciudad: "Boston",
   provincia: "CA",
   cp: "56789"
}
...

La ventaja de este planteamiento es que ademas permite una relación N:M, ya que la referencia de un departamento puede estár en el array de diferentes empleados.

Relaciones 1 a N (gran volumen)

Se emplean cuando un empleado se puede relacionar con un volumen muy grande de documentos de departamentos. La capacidad del array (16mb) limita la cantidad de referencias posibles a departamentos.

//Documento empleado
{
   _id: ObjectID("AAAA"),
   nombre: "Joe",
   apellidos: "Book Reader"
}
 
//Documentos de departamentos, guardan la referencia al empleado
{
   _id: ObjectId("ABCD")
   calle: "123 Fake Street",
   ciudad: "Faketon",
   provincia: "MA",
   cp: "12345"
   empleado: ObjectId("AAAA")  //Guarda la referencia al empleado
}
 
{
   _id: ObjectId("EFGH")
   calle: "1 Other Street",
   ciudad: "Boston",
   provincia: "CA",
   cp: "56789"
   empleado: ObjectId("AAAA")  //Guarda la referencia al empleado
}

Proyectos de ejemplo

  • Además podéis encontrar proyectos de ejemplo de aplicaciones Java que utilicen MongoDB en el repositorio de Santi Faci.

Prácticas

  • Práctica 4.1 Programar una aplicación que conecta con una Base de Datos NoSQL

© 2021 Santiago Faci y Fernando Valdeón

apuntes/mongodb.txt · Última modificación: 2020/09/30 09:15 (editor externo)