Сложное ограничение в Mongo / Mongoose - PullRequest
2 голосов
/ 01 мая 2020

Я работаю над проектом, который использует 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);



1 Ответ

1 голос
/ 01 мая 2020

Будет полезен хук предварительного сохранения для применения этого ограничения. Пожалуйста, проверьте ссылку

. Вы можете передать данные результата ограничения и выполнить действие в соответствии с тем, как документ должен быть сохранен или нет.

Для передачи данных в до и после сохранения вы можете проверить this

и многое другое о том, как именно работает промежуточное ПО. Ссылки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...