MongoDB在子文档上找到重叠的日期范围

时间:2019-07-24 09:16:55

标签: node.js mongodb express mongoose

假设我有此数据:

[{
    "name": "New Training1",
    "participants": ["5d2eca379b0d361b18d2f3d0", "5d31290c21729014a0bdd0ba"],
    "schedule": [{
        "start": "2019-10-07T12:00:00.000Z",
        "end": "2019-10-07T14:00:00.000Z"
    }]
}, {
    "name": "New Training2",
    "participants": ["5d2eca379b0d361b18d2f3d0"],
    "schedule": [{
        "start": "2019-10-07T14:00:00.000Z",
        "end": "2019-10-07T15:00:00.000Z"
    }]
}, {
    "name": "New Training3",
    "participants": ["5d31290c21729014a0bdd0ba"],
    "schedule": [{
        "start": "2019-10-07T14:00:00.000Z",
        "end": "2019-10-07T16:00:00.000Z"
    }]
}]

我想做的是,当我尝试将ID为5d2eca379b0d361b18d2f3d0的参与者添加到培训New Training3时,应用程序将抛出错误,表明日程安排存在冲突,并且将返回有冲突的时间表。根据上面的数据,系统必须返回此训练,因为它的时间表有冲突:

{
    "name": "New Training2",
    "participants": ["5d2eca379b0d361b18d2f3d0"],
    "schedule": [{
        "start": "2019-10-07T14:00:00.000Z",
        "end": "2019-10-07T15:00:00.000Z"
    }
}

这是我到目前为止所拥有的。

培训模式:

const mongoose = require('mongoose');
const ScheduleSchema = require('../models/schedule.model').schema;

const TrainingSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      unique: true,
      required: true
    },
    participants: [{ type: mongoose.Schema.ObjectId, ref: 'Participant' }],
    schedule: [ScheduleSchema]
  },
  {
    versionKey: false,
    timestamps: true
  }
);

module.exports = mongoose.model('Training', TrainingSchema);

参与者模型:

const mongoose = require('mongoose');

const ParticipantSchema = new mongoose.Schema(
  {
    name: {
      type: String,
      required: true
    }
  }
);

时间表模型

const mongoose = require('mongoose');

const ScheduleSchema = new mongoose.Schema(
  {
    start: {
      type: Date,
      required: true
    },
    end: {
      type: Date,
      required: true
    }
  },
  {
    versionKey: false,
    timestamps: false
  }
);

module.exports = mongoose.model('Schedule', ScheduleSchema);

如果我在给定的participantId的训练中添加了trainingId的实用性,则获得时间表重叠的训练的功能:

const model = require('../models/training.model');

exports.participantScheduleOverlaps = async (trainingId, participantId) => {
  return new Promise((resolve, reject) => {
    model.find(

    );
  });
};

我需要构建MongoDB查询来查找重叠的时间表。谢谢。

2 个答案:

答案 0 :(得分:1)

尝试这个。

const mongoose = require('mongoose')
const Schema = mongoose.Schema
const util = require("util")

mongoose.connect("mongodb://localhost/mongoose-doc", { useNewUrlParser: true })

const ScheduleSchema = new Schema(
    {
      start: {
        type: Date,
        required: true
      },
      end: {
        type: Date,
        required: true
      }
    },
    {
      versionKey: false,
      timestamps: false
    }
  );

const TrainingSchema = new Schema(
  {
    name: {
      type: String,
      unique: true,
      required: true
    },
    participants: [{ type: mongoose.Schema.ObjectId, ref: 'Participant' }],
    schedule: [ScheduleSchema]
  },
  {
    versionKey: false,
    timestamps: true
  }
);
const TrainingModel = mongoose.model("Training", TrainingSchema);

const ParticipantSchema = new Schema(
  {
    name: {
      type: String,
      required: true
    }
  }
);
const ParticipantModel = mongoose.model("Participant", ParticipantSchema)

async function participantScheduleOverlaps(trainingId, participantId) {

    try {
        const trainingWeFound = await TrainingModel.aggregate([
            {
                $match:{
                    _id: mongoose.Types.ObjectId(trainingId)
                }
            },
            {
                $unwind: "$schedule"
            }
        ]).exec()
        const otherTrainingModules = await TrainingModel.aggregate(
            [
                {
                    $match:{
                        $and:[
                            {
                                _id:{
                                    $ne: mongoose.Types.ObjectId(trainingId)
                                }
                            },
                            {
                                participants: {
                                    $in: [mongoose.Types.ObjectId(participantId)]
                                }
                            }
                        ]

                    }
                },
                {
                    $unwind: "$schedule"
                }
            ]
        ).exec()
        const overlapping = otherTrainingModules.filter((otherelem) => {
            return trainingWeFound.filter(foundelem => {
                (
                    Date.parse(otherelem.start) < Date.parse(foundelem.start) 
                    &&
                    Date.parse(foundelem.start) < Date.parse(otherelem.end)
                ) || (
                    Date.parse(otherelem.start) < Date.parse(foundelem.end) 
                    &&
                    Date.parse(foundelem.end) < Date.parse(otherelem.end)
                )
            })
        })

        console.log("overlapping", overlapping)

    } catch(error){
        console.log(error)
    }
}
participantScheduleOverlaps("5d395604eb41824b5feb9c84", "5d31290c21729014a0bdd0ba")

答案 1 :(得分:0)

这是我针对可能有相同或相关问题的任何人的解决方案:

exports.participantScheduleOverlaps = async (trainingId, participantId) => {
  return new Promise((resolve, reject) => {
    model.findById(trainingId, (error, item) => {
      const result = {
        overlap: false,
        ranges: []
      };

      if (error) {
        reject(utils.buildErrObject(422, error.message));
      }

      if (item) {
        for (const schedule of item.schedule) {
          model.find(
            {
              _id: { $ne: trainingId },
              participants: { $eq: participantId },
              'schedule.end': { $gt: schedule.start },
              'schedule.start': { $lt: schedule.end }
            },
            (err, items) => {
              if (err) {
                reject(utils.buildErrObject(422, err.message));
              }

              if (items.length > 0) {
                result.overlap = true;
                result.ranges.push(
                  ...items.map(data => {
                    return data.schedule;
                  })
                );
              }

              resolve(result);
            }
          );
        }
      } else {
        resolve(result);
      }
    });
  });
};