Mongoose Dynamic References(Polymorphic Reference)
Me encontré con un caso particular en el que un usuario podía tener uno de dos tipos de roles(alumno o profesor), los dos debían hacer login desde el mismo endpoint y para registrarse lo hacían con los mismos datos(correo, nombre y apellidos), la diferencia entre estos sucede al llenar un perfil correspondiente a su rol, por ejemplo: de uno guardamos su cuota mensual y del otro las horas de trabajo.
Para cubrir estos requerimientos con un modelo NoSQL encontré la siguiente solución como lo que mejor se acomoda al resultado requerido:
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
email: String,
password: String,
name: String,
lastname: String
role: {
type: mongoose.Schema.Types.ObjectId,
refPath: 'roleType'
},
roleType:{
type: String,
enum: ['Teacher', 'Student']
}
});
Siendo roleType el tipo de rol(el cual a su vez es el nombre del modelo que guardará la información extra) y role el ObjectId correspondiente a la colección a la que se hace referencia. Con esta solución fue necesario crear dos modelos extra para guardar los datos de los roles especificados en el roleType.
const StudentRoleSchema = new mongoose.Schema({
birthDate: Date,
tutor: String,
annualEnrollment: Number,
monthlyTuition: Number,
});
const TeacherRoleSchema = new mongoose.Schema({
weeklyTotalHours: Number,
contract: String,
});
Para utilizar este modelo, se puede seguir el código siguiente:
const updateStudentRole = async() {
const updateObj = {birthDate: '2018-10-04',
tutor: 'Someone',
annualEnrollment: 1500,
monthlyTuition: 1200
};
let user = await User.findById(req.body.id);
let studentRole = await StudentRole.findOneAndUpdate({
_id: user.role
}, updateObj);
const student = await Student.create(updateObj);
user = await User.findByIdAndUpdate(args.id, {
role: student.id
}, {new: true});
return user;
}
De esta manera se pueden guardar o actualizar los datos específicos del rol y en caso de que un estudiante pase a ser profesor. Su rol puede ser actualizado sin tener que generar un nuevo usuario.