Mongodb:如果时隙不与其他时隙冲突,则查找并插入

时间:2018-02-14 07:44:45

标签: javascript node.js mongodb mongoose

我有一个事件架构:

owner: {
    type: Schema.Types.ObjectId,
    ref: 'User',
    required: true
},
participants: [
    {
        type: Schema.Types.ObjectId,
        ref: 'User'
    }
],
createdOn: { type: Date, default: Date.now },
lastModified: { type: Date, default: Date.now },
active:{ type: Boolean, default: false },
eventDate: { type: Date },
startAt: { type: Date },
endAt : { type: Date },
timeZone:{ type: 'String', required: true }

我想插入事件,使事件不与其他事件重叠(例如:如果事件是在2018-2-14开始于凌晨3:00结束于凌晨4:00,则应该没有事件这个日期在凌晨3点到凌晨4点之间,除了这个事件。但是在这个日期可能有其他时间段的事件,但不是在凌晨3点到凌晨4点之间。

我尝试了以下逻辑,但我似乎没有工作。这个逻辑错了:

const eventData = {
    owner: req
        .body
        .owner
        .trim(),
    startAt: setTimeToDate(req.body.eventDate, req.body.startAt.trim(), req.body.timeZone),
    endAt: setTimeToDate(req.body.eventDate, req.body.endAt.trim(), req.body.timeZone),
    eventDate: moment(req.body.eventDate).toISOString(),
    participants: req.body.participants,
    active: true,
    timeZone: req.body.timeZone
};

Events.find({
    $and: [
        {
            "eventDate": new Date(eventData.eventDate)
        }, {
            $or: [
                {
                    $and: [
                        {
                            "startAt": {
                                $lt: new Date(eventData.startAt)
                            }
                        }, {
                            "startAt": {
                                $lte: new Date(eventData.endAt)
                            }
                        }
                    ]
                }, {
                    $and: [
                        {
                            "endtAt": {
                                $gte: new Date(eventData.startAt)
                            }
                        }, {
                                "endtAt": {
                                    $gt: new Date(eventData.endAt)
                                }
                            }
                        ]
                }
                ]
        }

        ]
})
    .exec(function (err, results) {
        const count = results.length;
        if (!count) {
            const newEvent = new Events(eventData);
            newEvent.save((err) => {
                if (err) {
                    res
                        .status(400)
                        .json({success: false, message: 'Could not create this availability.'});
                }
                res
                    .status(200)
                    .send({success: true, message: 'Your availability on this date is created successfully.'});
            });
        }

    });

2 个答案:

答案 0 :(得分:1)

好吧,我不确定,但我发现逻辑中存在两个缺陷

基本上你需要任何在你的新startAt和endAt之间有startAt或endAt的记录

在第一个条件中,你想要在新的startAt和endAt之间有startAt时间的插槽,那么逻辑就是

startAt greater than new startAt and less than equal to new endAt
$and: [
                    {
                        "startAt": {
                            $gt: new Date(eventData.startAt)
                        }
                    }, {
                        "startAt": {
                            $lte: new Date(eventData.endAt)
                        }
                    }
                ]

此外,您需要在new startAt之后和new endAt之前具有endAt的记录,因此该逻辑将是

endAt greater than new startAt and less than equal to new endAt
    $and: [
                        {
                            "endAt": {
                                $gt: new Date(eventData.startAt)
                            }
                        }, {
                            "endAt": {
                                $lte: new Date(eventData.endAt)
                            }
                        }
                    ]

我认为这会奏效。

编辑好的第三个条件是,Slots在新的StartAt之前开始并在新的EndAt之后结束,因为它们不会落入上述条件

  $and: [
                            {
                                "startAt": {
                                    $lt: new Date(eventData.startAt)
                                }
                            }, {
                                "endAt": {
                                    $gt: new Date(eventData.endAt)
                                }
                            }
                        ]

答案 1 :(得分:0)

So what I did was to find out the chances that an event can overlap with other events.

The first case is when the start time of the new event that I'm gonna insert is between start time and end time of any other events.

The second case is similar and the only difference is this time I check if the end time of the new event that I'm gonna insert is between the start time and end time of any other events.

The third case is when the start time of the new event is less than the start time of any other events and the end time of new event is greater than the end time of any other events.

The 3 above scenarios cover all the cases of time slot overlappping The query for the same is as shown below

{
            $or: [
                {
                    $and: [
                        {
                            "startAt": {
                                $lte: new Date(new Date(eventData.startAt))
                            }
                        }, {
                            "endAt": {
                                $gte: new Date(new Date(eventData.startAt))
                            }
                        }
                    ]
                }, {
                    $and: [
                        {
                            "startAt": {
                                $lte: new Date(new Date(eventData.endAt))
                            }
                        }, {
                            "endAt": {
                                $gte: new Date(new Date(eventData.endAt))
                            }
                        }
                    ]
                }, {
                    $and: [
                        {
                            "startAt": {
                                $gte: new Date(new Date(eventData.startAt))
                            }
                        }, {
                                "endAt": {
                                    $lte: new Date(new Date(eventData.endAt))
                                }
                            }
                        ]
                }
                ]
        }