我有许多文档,其架构如下所示,每个文档都包含(开始日期,结束日期),如下架构所示。有没有一种简单的方法可以在保存新文档之前知道新文档的开始日期、结束日期是否会与以前保存的文档开始日期、结束日期重叠?
{
"title" : "",
"owner" : "",
"notes" : "",
"startdate" : "",
"enddate" : ""
}
以下是当前保存的唯一文档:
Document.(anonymous function) {_id: "FADnPAxRu4Ps5hkLz",
title: "Round A",
customerid: "QDGvBQhS6vYgZtnRr",
startdate: "11/21/2014 7:25 AM"…}
_id: "FADnPAxRu4Ps5hkLz"customerid: "QDGvBQhS6vYgZtnRr"
enddate: "11/30/2014 6:09 AM"
startdate: "11/21/2014 7:25 AM"
title: "Round A"__proto__: Document.(anonymous function)
当我尝试在上述文档上执行以下任何查询时,它不会返回任何内容,即使这里有明显的重叠。
db.Projects.find({'startdate': {$lt: '11/25/2014 6:26 PM'}, 'enddate': {$gt: '11/19/2014 6:26 PM'}}, {sort:{time: -1}});
db.Projects.find({'startdate': {$lt: '11/30/2014 6:26 PM'}, 'enddate': {$gt: '11/21/2014 6:26 PM'}}, {sort:{time: -1}});
时间重叠可以用下图中的这 4 种情况来说明,其中 S/E 是新文档的开始日期/结束日期,S'/E' 是任何现有文档的开始日期/结束日期:
S' E'
|-------------------|
S E
|****************|
S' E'
|-----------|
S' E'
|-----------|
S' E'
|-----------|
在 4 种情况下,我们有
S'<E
和 E'>S
。查找所有时间重叠的文档的查询可以是:
db.collection.find({"startdate": {"$lt": E}, "enddate": {"$gt": S}})
编辑:
您的开始日期和结束日期是字符串格式,并且没有按词汇顺序排列,因此不能使用“$gt”和“$lt”进行比较。您应该将它们转换为日期类型:
db.collection.find().forEach(
function (e) {
// convert date if it is a string
if (typeof e.startdate === 'string') {
e.startdate = new Date(e.startdate);
}
if (typeof e.enddate === 'string') {
e.enddate = new Date(e.enddate);
}
// save the updated document
db.collection.save(e);
}
)
最终查询将是:
db.collection.find({"startdate": {"$lt": new Date("E")}, "enddate": {"$gt": new Date("S")}})
在已接受答案的帮助下,我能够将所有四种情况融合在一起,并提出一个完美的解决方案。希望它可以帮助其他人。
S E
|****************|
S1 E1
|----------------------|
S2 E2
|----------|
S3 E3
|-----------|
S4 E4
|-------------|
情况1:间隔完全覆盖开始日期和结束日期
{ "startDate": { $lte: moment(S1).toDate() } }
{ "endDate": { $gte: moment(E1).toDate() } }
情况2:间隔完全在开始日期和结束日期内
{ "startDate": { $gte: moment(S2).toDate() } }
{ "endDate": { $lte: moment(E2).toDate() } }
情况 3:开始日期在区间外,结束日期在区间内
{ "endDate": { $gte: moment(S3).toDate() } }
{ "endDate": { $lte: moment(E3).toDate() } }
情况 4:开始日期在区间内,结束日期在区间外
{ "startDate": { $gte: moment(S4).toDate() } }
{ "startDate": { $lte: moment(E4).toDate() } }
用“$and”和“$or”组合所有四种情况,以获得至少满足一种情况的数据。
const query = {};
const datePipeArray = [];
datePipeArray.push({ "$and":[
{ "startDate": { $gte: moment(queryStartDate).toDate() } },
{ "endDate": { $lte: moment(queryEndDate).toDate() } }
]});
datePipeArray.push({ "$and":[
{ "endDate": { $gte: moment(queryStartDate).toDate() } },
{ "endDate": { $lte: moment(queryEndDate).toDate() } }
]});
datePipeArray.push({ "$and":[
{ "startDate": { $gte: moment(queryStartDate).toDate() } },
{ "startDate": { $lte: moment(queryEndDate).toDate() } }
]});
datePipeArray.push({ "$and":[
{ "startDate": { $lte: moment(queryStartDate).toDate() } },
{ "endDate": { $gte: moment(queryEndDate).toDate() } }
]});
query["$or"] = datePipeArray;
db.calendar.find(query)
P.S:时刻是可选的