Javascript Mongo/Mongoose中的复杂约束
我正在从事一个使用Mongo/Mongoose/NodeJS的项目 我对数据库中的数据有一个相对复杂的约束要求,我不确定它是否能够实现 我的模式如下:Javascript Mongo/Mongoose中的复杂约束,javascript,node.js,database,mongodb,mongoose,Javascript,Node.js,Database,Mongodb,Mongoose,我正在从事一个使用Mongo/Mongoose/NodeJS的项目 我对数据库中的数据有一个相对复杂的约束要求,我不确定它是否能够实现 我的模式如下: const schema = new Schema( { id: ObjectId, date: { type: Date, required: true, unique: true, }, eventType: { type: String, enu
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,
},
},
);
所需的逻辑是:
事件类型在每个日历年只能存在一次,除非事件类型为“GROUP_STAGE”,它可以在一个日历年中存在多次
我对猫鼬/猫鼬很缺乏经验,但是我觉得这种限制可能是不可能的
如果插入/更新是唯一的方法,我可以在插入/更新之前将逻辑放在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);
预保存挂钩以应用此约束将非常有用。请检查一下电话号码 您可以传递约束结果的数据,并根据这些数据执行操作,例如文档是否应保存 要在保存前和保存后传递数据,可以检查
以及更多关于中间件工作原理的信息 可以使用预保存挂钩应用此约束。请查看“感谢您的回复”!我看过pre,它似乎很有用,“正确”的做法是从“pre”函数中对现有文档运行查询,并使用查询结果与要插入的文档进行比较吗?还是有更好的方法从“pre”功能中访问现有文档?答案中添加了更多的资源和想法。希望这会有所帮助。非常感谢您提供的信息。我正在努力解决的一件事是如何将插入的文档的属性与数据库中已有文档的属性进行比较?如中所示,我想插入{date:'01-01-2020','eventType':'FINAL'},并且需要检查数据库中2020年没有任何其他eventType为finals的条目。因此,在预保存钩子中,您可以访问req对象,从那里您可以获得想要输入的数据。然后,您可以使用find查询查看是否存在满足条件的文档。你需要那个问题的帮助吗?