【发布时间】:2020-08-15 20:00:11
【问题描述】:
我正在开发一个使用 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,
},
},
);
需要的逻辑是:
一个 eventType 在每个日历年只能存在一次,除非 eventType 是“GROUP_STAGE”,它可以在一个日历年内存在多次。
我对 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,
},
},
);
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);
【问题讨论】:
-
您可以使用预保存挂钩来应用此约束。请查看reference
-
感谢您的回复!我已经查看了 pre 并且它似乎很有用 - “正确”的做法是从“pre”函数中对现有文档运行查询并使用查询结果与文档进行比较被插入?还是有更好的方法从“pre”函数中访问现有文档?
-
在答案中添加了更多资源和想法。希望这可能会有所帮助。
标签: javascript node.js database mongodb mongoose