Я работаю над проектом, который использует Mongo / Mongoose / NodeJS.
У меня есть требование относительно сложного ограничения для данных в БД, и я не уверен, возможно ли это вообще реализовать.
Моя схема выглядит следующим образом:
const schema = new Schema(
{
id: ObjectId,
date: {
type: Date,
required: true,
unique: true,
},
eventType: {
type: String,
enum: ['GROUP_STAGE', 'ROUND_OF_16', 'QUARTER_FINAL', 'SEMI_FINAL', 'FINAL'],
required: true,
},
},
);
Требуемый лог c:
EventType может существовать только один раз в течение календарного года. , если eventType не равен 'GROUP_STAGE', который может существовать несколько раз в течение календарного года.
Я довольно неопытен с Mongo / Mon goose, однако я чувствую, что это ограничение может невозможно.
Я могу поместить logi c в слой NodeJS перед вставкой / обновлением, если это единственный способ сделать это, однако это выглядит немного хакерским и хрупким.
Если ответом на это требование является «это невозможно», я все равно буду благодарен за подтверждение.
РЕДАКТИРОВАТЬ - Решение, следуя рекомендациям в принятом ответе
const schema = new Schema(
{
id: ObjectId,
date: {
type: Date,
required: true,
unique: true,
},
eventType: {
type: String,
enum: ['GROUP_STAGE', 'ROUND_OF_16', 'QUARTER_FINAL', 'SEMI_FINAL', 'FINAL'],
required: true,
},
},
);
const getFindDuplicateEventTypeInASingleYearQuery = (values) => {
const { id, eventType, year } = values;
const query = {
eventType,
date: {
$gte: new Date(`${year}-01-01T00:00:00.000Z`),
$lt: new Date(`${year}-12-31T23:59:59.999Z`),
},
};
// If an id is supplied, exclude it from the query
// This is to prevent false flags when updating an object
if (id) {
query._id = { $ne: new mongoose.Types.ObjectId(id) };
}
return query;
};
const checkForInvalidDuplicateEventTypeInYear = async (queryValues, model) => {
if (queryValues.eventType !== 'GROUP_STAGE') {
const query = getFindDuplicateEventTypesInASingleYearQuery(queryValues);
const count = await model.countDocuments(query);
if (count > 0) {
return new Error(`There is already a fixture with the eventType ${queryValues.eventType} in ${queryValues.year}`);
}
}
return null;
};
async function handlePreSave(next) {
next(
await checkForInvalidDuplicateEventTypeInYear(
{
eventType: this.eventType,
year: this.date.getFullYear(),
},
this.constructor,
),
);
}
async function handlePreFindOneAndUpdate(next) {
const { eventType, date } = this.getUpdate();
next(
await checkForInvalidDuplicateEventTypeInYear(
{
id: this.getQuery()._id,
eventType,
year: date.split('-')[0],
},
this.model,
),
);
}
schema.pre('save', handlePreSave);
schema.pre('findOneAndUpdate', handlePreFindOneAndUpdate);
module.exports = mongoose.model('Fixture', schema);