使用两个日期比较而不是日期范围查询在 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")
        }}
    ]
});

这是允许的,因为每个元素都在它自己的文档中并且是数组的成员。此处的分隔允许您在每个元素中使用相同的键名。