Creación de relaciones entre documentos de una base de datos MongoDB con Mongoose

2
10335

En este tutorial con la ayuda de Mongoose aprenderemos a “crear relaciones” entre diferentes documentos extraídos de una base de datos NoSql cómo MongoDB.

Índice de contenidos

1. Introducción

Actualmente estoy desarrollando una pequeña API con NestJS y MongoDB. Uno de los “problemas” que me encontré fue a la hora de devolver objetos anidados.

Gracias a Mongoose esto no será un problema.

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil MacBook Pro 15′ (2,7 Ghz Intel Core i7, 16GB DDR3).
  • Sistema Operativo: Mac OS Catalina 10.15.3
  • Entorno de desarrollo: Visual Studio Code
  • NestJS 6.14.2
  • TypeScript 3.7.4

3. ¿Que es mongoose?

Mongoose es una biblioteca que nos permite definir esquemas en nuestra API con la misma estructura que se está utilizando en nuestros documentos de MongoDB.

4. Instalación y configuración

Usando npm podemos instalarlo

npm i mongoose

Una vez instalado procedemos a definir nuestra conexión con la base de datos, en este caso estamos utilizando MongoDB.

Debemos importar en el app.module de nuestro proyecto el módulo de mongoose y asignarle la conexión a nuestra base de datos.

MongooseModule.forRoot('mongodb://localhost/mongodb_test')

Ahora debemos definir nuestros esquemas, en mi caso son dos: alumno y curso.

El esquema alumno será el encargado de tener la referencia al documento de curso.

  • Alumno
import * as mongoose from 'mongoose';
export const StudentSchema = new mongoose.Schema({
 name: String,
 surname: String,
 courses: [
   {
     type: mongoose.Schema.Types.ObjectId,
     ref: 'Course',
   },
 ],
});

En el esquema alumno podemos ver que tiene como atributo un array de cursos debido a que un alumno puede estar inscrito en diferentes cursos. Hacemos referencia a un objeto de tipo Course.

  • Curso
import * as mongoose from 'mongoose';

export const CourseSchema = new mongoose.Schema({
 name: String,
});

En el esquema curso tenemos simplemente su nombre.

No es necesario asignarles una id ya que Moongose se encarga de hacerlo.

4.1. Populate

Una vez realizados los esquemas ya podremos agregar en nuestro servicio de alumno, que es el encargado de realizar la consulta en la base de datos, la llamada al método populate() que nos permitirá anidar el objeto alumno con sus respectivos cursos.

async getStudents(): Promise<Student[]> {
return this.studentModel.find()
.populate({ path: 'courses', model: 'Course' })
.exec();
   }

 

En el método encargado de recoger todos los alumnos le decimos que queremos poblar esa lista de alumnos con los datos del documento cursos de la base de datos, cuyo id del curso sea el mismo que aparece en el array de cursos de los alumnos. De esta manera es cómo Mongoose nos permite realizar esta relación.

4.2. Realizando la petición

Una vez definido nuestro endpoint en el controlador, podremos realizar la petición y ver el resultado.

[
  {
    "courses": [
      {
        "_id": "5e454efb7e322f0012fa11b5",
        "name": "curso_java"
       }],
    "_id": "5e454efb7e322f0012fa13h6",
    "name": "Autentia",
    "surname": "Real Business Solutions",
    "__v": 0
    }
]

4.3. Utilizando mongoose-autopopulate

Otra forma que tenemos de hacer este “populate” es con el plugin mongoose-autopopulate.

npm i mongoose-autopopulate

Una vez instalada, su uso es muy fácil, basta con agregar en nuestro esquema:

import * as mongoose from 'mongoose';

export const StudentSchema = new mongoose.Schema({
 name: String,
 surname: String,
 courses: [
   {
     type: mongoose.Schema.Types.ObjectId,
     ref: 'Course',
     autopopulate: true,
   },
 ],
});

StudentSchema.plugin(require('mongoose-autopopulate'));

Con esto ya no tendríamos qué hacer nada más.

5. Conclusiones

Trabajar con una base de datos como MongoDB por primera vez puede resultar raro, pero con la ayuda de Mongoose esta tarea se vuelve mucho más fácil.

6. Referencias

2 COMENTARIOS

  1. hola, que tal, gracias por el aporte…
    puede hacer este ejemplo.

    La cuestión es que es estoy intentando hacer una consulta especifica donde pueda traerme solo los estudiantes con el curso matemática para después mostrar en pantalla los estudiantes ordenados por curso. No e podido resolver este dilema, te agradecería tu ayuda de ante mano..

    esta es mi consulta, pero no funciona con ese find()
    Controller.listarAlumno = async (req,res) => {
    const estudiantes = await Alumno.find({«curso.nombrecurso»:»ingles»}})
    .populate({ path: ‘curso’, model: ‘Curso’ })
    .exec();
    return res.json(estudiantes);

    • Hola Manuel, muchas gracias por leer el tutorial y espero que te sirva 😉

      El error que tienes es porque quieres encontrar algo que se encarga de devolverte el .populate().

      La solución seria dejar el find() vacío y colocar el filtro en el populate y ayudarnos de la condición match.

      Quedaria así:

      const estudiantes = await Alumno.find()
      .populate({ path: ‘curso’, model: ‘Curso’, match: {nombrecurso : ‘ingles’}}})
      .exec()

      En la documentación puedes encontrarlo: https://mongoosejs.com/docs/populate.html#query-conditions

      Espero haberte ayudado 😉

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad