使用两个日期比较而不是日期范围查询在 MongoDB 中给出不同的结果
Using two date comparisons instead of date range query gives different results in MongoDB
像这样的对象:
{
"status" : 1,
"date" : ISODate("2014-02-13T13:00:31.233Z")
}
为什么这个范围查询
db.collection.find({
"status": 1,
"date": {
$lte: ISODate("2015-06-16T20:05:03.000Z"),
$gte: ISODate("2015-06-15T20:05:03.000Z")
}
});
给出正确的结果,而这两个日期比较给出不同的结果:
db.collection.find({
"status": 1,
"date": {
$lte: ISODate("2015-06-16T20:05:03.000Z")
},
"date": {
$gte: ISODate("2015-06-15T20:05:03.000Z")
}
});
看起来最后一个查询实际上以日期比较之间的 OR 结束,而不是我预期的 AND。
find({"status" : 1, "date":{ $lte:ISODate("2015-06-16T20:05:03.000Z")},"date":{$gte:ISODate("2015-06-15T20:05:03.000Z")}})
;
此处您试图查找小于 2015-06-16T20:05:03.000Z 的日期(键),并且在同一个查询中您将日期(键)添加到 2015-06-15T20:05:03.000Z。
你只有一把钥匙作为日期。
以上查询的行为类似于 select * 来自 table where date >=2015-06-15T20:05:03.000Z and date <= 2015-06-15T20:05:03.000Z
但第一个查询以一个日期为键并取多个值进行比较。
之所以不一样,是因为您违反了 "hash/map" 结构的一般规则,该规则也适用于 JavaScript 对象。该规则表示 "key" 只能指定 一次。
当你这样写的时候:
db.collection.find({
"status": 1,
"date": {
"$lte": ISODate("2015-06-16T20:05:03.000Z")
},
// The next same key overwrites the other one
"date": {
"$gte": ISODate("2015-06-15T20:05:03.000Z")
}
});
"date"
项中的一项 "ignored" 因为每个级别只能有一个。因此,实际上 "less than" 或 "greater than" 被作为条件丢弃(可能是 "less than" 因为它是第一个)并且所有文档仅针对单个条件进行测试。
这是一个很好的例子。考虑这些文档:
{ "a": 1 },
{ "a": 2 },
{ "a": 3 },
{ "a": 4 }
当您发出此查询时:
db.collection.find({ "a": { "$gte": 2 }, "a": { "$lte": 3 } },{ "_id": 0 })
结果仅匹配 "second" 条件,因为该键覆盖了 "first"。它显然违反了 "first" 条件,所以这表明它是 "discarded":
{ "a": 1 }
{ "a": 2 },
{ "a": 3 },
因此,为了获得两个条件应用,您需要像之前那样指定:
db.collection.find({
"status": 1,
"date": {
"$lte": ISODate("2015-06-16T20:05:03.000Z"),
"$gte": ISODate("2015-06-15T20:05:03.000Z")
}
});
这实际上是 "shorthand" 写这个:
db.collection.find({
"status": 1,
"$and": [
{ "date": {
"$lte": ISODate("2015-06-16T20:05:03.000Z")
}},
{ "date": {
"$gte": ISODate("2015-06-15T20:05:03.000Z")
}}
]
});
这是允许的,因为每个元素都在它自己的文档中并且是数组的成员。此处的分隔允许您在每个元素中使用相同的键名。
像这样的对象:
{
"status" : 1,
"date" : ISODate("2014-02-13T13:00:31.233Z")
}
为什么这个范围查询
db.collection.find({
"status": 1,
"date": {
$lte: ISODate("2015-06-16T20:05:03.000Z"),
$gte: ISODate("2015-06-15T20:05:03.000Z")
}
});
给出正确的结果,而这两个日期比较给出不同的结果:
db.collection.find({
"status": 1,
"date": {
$lte: ISODate("2015-06-16T20:05:03.000Z")
},
"date": {
$gte: ISODate("2015-06-15T20:05:03.000Z")
}
});
看起来最后一个查询实际上以日期比较之间的 OR 结束,而不是我预期的 AND。
find({"status" : 1, "date":{ $lte:ISODate("2015-06-16T20:05:03.000Z")},"date":{$gte:ISODate("2015-06-15T20:05:03.000Z")}})
;
此处您试图查找小于 2015-06-16T20:05:03.000Z 的日期(键),并且在同一个查询中您将日期(键)添加到 2015-06-15T20:05:03.000Z。 你只有一把钥匙作为日期。
以上查询的行为类似于 select * 来自 table where date >=2015-06-15T20:05:03.000Z and date <= 2015-06-15T20:05:03.000Z
但第一个查询以一个日期为键并取多个值进行比较。
之所以不一样,是因为您违反了 "hash/map" 结构的一般规则,该规则也适用于 JavaScript 对象。该规则表示 "key" 只能指定 一次。
当你这样写的时候:
db.collection.find({
"status": 1,
"date": {
"$lte": ISODate("2015-06-16T20:05:03.000Z")
},
// The next same key overwrites the other one
"date": {
"$gte": ISODate("2015-06-15T20:05:03.000Z")
}
});
"date"
项中的一项 "ignored" 因为每个级别只能有一个。因此,实际上 "less than" 或 "greater than" 被作为条件丢弃(可能是 "less than" 因为它是第一个)并且所有文档仅针对单个条件进行测试。
这是一个很好的例子。考虑这些文档:
{ "a": 1 },
{ "a": 2 },
{ "a": 3 },
{ "a": 4 }
当您发出此查询时:
db.collection.find({ "a": { "$gte": 2 }, "a": { "$lte": 3 } },{ "_id": 0 })
结果仅匹配 "second" 条件,因为该键覆盖了 "first"。它显然违反了 "first" 条件,所以这表明它是 "discarded":
{ "a": 1 }
{ "a": 2 },
{ "a": 3 },
因此,为了获得两个条件应用,您需要像之前那样指定:
db.collection.find({
"status": 1,
"date": {
"$lte": ISODate("2015-06-16T20:05:03.000Z"),
"$gte": ISODate("2015-06-15T20:05:03.000Z")
}
});
这实际上是 "shorthand" 写这个:
db.collection.find({
"status": 1,
"$and": [
{ "date": {
"$lte": ISODate("2015-06-16T20:05:03.000Z")
}},
{ "date": {
"$gte": ISODate("2015-06-15T20:05:03.000Z")
}}
]
});
这是允许的,因为每个元素都在它自己的文档中并且是数组的成员。此处的分隔允许您在每个元素中使用相同的键名。