Mongo/Mongoose 中的复杂约束

Posted

技术标签:

【中文标题】Mongo/Mongoose 中的复杂约束【英文标题】:Complex constraint in Mongo/Mongoose 【发布时间】: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”函数中访问现有文档? 在答案中添加了更多资源和想法。希望这可能会有所帮助。 【参考方案1】:

应用此约束的预保存挂钩会很有帮助。请查看reference

您可以传递约束结果的数据,并根据是否保存文档进行操作。

要在保存前和保存后传递数据,您可以查看this

还有更多关于中间件是如何工作的。 Reference

【讨论】:

非常感谢您提供的信息。我正在努力解决的一件事是如何将我插入的文档的属性与数据库中已有文档的属性进行比较?如中,我想插入 date: '01-01-2020', 'eventType': 'FINAL' 并需要检查数据库中是否没有任何其他 2020 年 eventType 为 final 的条目 因此在预保存挂钩中,您可以从那里访问 req 对象,您可以获取要输入的数据。然后您可以使用查找查询来查看是否有满足条件的文档。您需要有关该查询的帮助吗?

以上是关于Mongo/Mongoose 中的复杂约束的主要内容,如果未能解决你的问题,请参考以下文章

无法通过 Mongo(mongoose)中的点符号搜索子文档 [重复]

如何从服务器端 express/mongo/mongoose 中的 URL,客户端的 axios/react/redux 中获取参数 ID

Mongoose/Mongo:更新不保存

Mongo/Mongoose 快速更新导致数据丢失

如何承诺 Mongo/Mongoose 找到

(Mongo/Mongoose) 如何处理等待多个查询的结果