У меня есть следующая схема ресурса:
const mongoose = require('mongoose');
const { Url } = require('./url');
const { Img } = require('./img');
/**
* Base learning resource model. Contains common fileds for all submodels
*/
// exported for using in other models
const discriminatorOptons = {discriminatorKey: 'kind'}
const options = {timestamps: true};
const resourceSchema = mongoose.Schema({
title: {
type: String,
required: true,
trim: true
},
finishBefore: {
type: Date,
require: false
},
reviewRating: {
type: Number,
require: false,
min: [1, 'Rating cannot be less than 1.'],
max: [10, 'Rating cannot be more than 10.'],
validate: {
validator: Number.isInteger,
message: '{VALUE} is not an integer'
}
},
review: {
type: String,
required: false,
},
additionalNotes: {
type: String,
required: false
},
authors: {
type: String,
required: false
},
isDone: {
type: Boolean,
default: false
},
urls: [Url],
images: [Img]
}, {...discriminatorOptons, ...options});
const Resource = mongoose.model('Resource', resourceSchema);
exports.Resource = Resource;
exports.discriminatorOptons = discriminatorOptons;
Это базовая схема для читаемых, носителей и т. Д. c типов -> у каждого типа будет свое собственное дополнительное поле. Например, читаемая схема (имеет дополнительные страницы и поля текущих страниц):
const mongoose = require('mongoose');
const {Resource, discriminatorOptons} = require('./resource');
/**
* Readable resource such as books, articles.
*/
const readebleSchema = mongoose.Schema({
pages: {
type: Number,
require: false
},
currentPage: {
type: Number,
require: false
}
});
const Readable = Resource.discriminator('Readable', readebleSchema, discriminatorOptons);
exports.Readable = Readable;
Модель пользователя имеет встроенный массив базового типа ресурса:
const { Resource } = require('./resource');
/**
* User model
*/
const userSchema = mongoose.Schema({
name: {
type: String,
required: true,
trim: true
},
email: {
type: String,
required: true,
unique: true,
lowercase: true,
validate: value => {
if (!validator.isEmail(value)) {
throw new Error({ error: 'Invalid Email address' });
}
}
},
password: {
type: String,
required: true,
minLength: 7,
select: false
},
tokens: {
type: [{
token: {
type: String,
required: true
},
}],
select: false
},
resources: {
type: [Resource.schema],
select: false
}
});
Контроллер для создания ресурса:
const { User } = require('../models');
const { resourceFactoryMethod } = require('../utils');
/**
* Create learning resource
*/
const create = async ({user, body}, res) => {
try {
const Model = resourceFactoryMethod(body.kind);
const resource = Model(body);
await User.addResourceToUser(user.id, resource);
res.status(201).send(resource);
} catch(error) {
res.status(400).send({error});
}
}
И заводской метод:
const {Base, Readable} = require('../models');
const resourceFactoryMethod = (kind) => {
switch(kind) {
case 'Base': return Base;
case 'Readable': return Readable;
default: throw Error('Kind of learning resource does not supported');
}
};
Нет ошибок. Но все ресурсы имеют только базовые типы, без дополнительных полей