在mongodb中使用ISODate进行日期查询似乎不起作用。

240

我似乎无法在MongoDB中实现最基本的日期查询。具体而言,有一个类似于以下文档的数据:

{
    "_id" : "foobar/201310",
    "ap" : "foobar",
    "dt" : ISODate("2013-10-01T00:00:00.000Z"),
    "tl" : 375439
}

而一个看起来像这样的查询:

{ 
    "dt" : { 
        "$gte" : { 
            "$date" : "2013-10-01T00:00:00.000Z"
        }
    }
}

我执行后得到0个结果

db.mycollection.find({
  "dt" : { "$gte" : { "$date" : "2013-10-01T00:00:00.000Z"}}
})

有任何想法为什么这不起作用吗?
供参考,此查询是由Spring的MongoTemplate生成的,因此我无法直接控制最终发送到MongoDB的查询。

(P.S.)

> db.version()
2.4.7

谢谢!

11个回答

395

虽然$dateMongoDB扩展JSON的一部分,并且在使用mongoexport时默认会得到它,但我认为你不能将其作为查询的一部分。

如果尝试使用以下精确搜索:$date

db.foo.find({dt: {"$date": "2012-01-01T15:00:00.000Z"}})

你会收到错误信息:

error: { "$err" : "invalid operator: $date", "code" : 10068 }

试试这个:

db.mycollection.find({
    "dt" : {"$gte": new Date("2013-10-01T00:00:00.000Z")}
})

或者(根据@user3805045的评论):

db.mycollection.find({
    "dt" : {"$gte": ISODate("2013-10-01T00:00:00.000Z")}
})

ISODate也可能需要用于比较不含时间的日期(由@MattMolnar指出)。

根据mongo Shell中的数据类型,两者应当是等价的:

mongo shell提供了各种方法来返回日期,可以返回字符串或Date对象:

  • Date()方法将当前日期作为字符串返回。
  • new Date()构造函数使用ISODate()包装器返回一个Date对象。
  • ISODate()构造函数使用ISODate()包装器返回一个Date对象。

并且使用ISODate仍然应该返回一个Date对象

{"$date": "ISO-8601 string"}在需要严格的JSON表示时可用。一个可能的例子是Hadoop连接器。


3
好的,我会尽力进行翻译。当你在Spring中打印Query对象时,返回的内容把我搞糊涂了。查询的序列化形式不一定是一个有效的查询,你不能直接复制/粘贴到Mongo shell中,这本身就令人沮丧。问题出在这里:http://grepcode.com/file/repo1.maven.org/maven2/org.mongodb/mongo-java-driver/2.8.0/com/mongodb/util/JSONSerializers.java#208 - Jason Polites
2
当比较一个部分日期(没有时间)时,我不得不从 new Date('2016-03-09') 切换到 ISODate('2016-03-09')。前者会在 $gte 查询中返回过去的日期。 - Matt Molnar
@MattMolnar 已经注意到了,并且已经在答案中加上了署名。谢谢。 - zero323

114

来自MongoDB cookbook页面的评论:

"dt" : 
{
    "$gte" : ISODate("2014-07-02T00:00:00Z"), 
    "$lt" : ISODate("2014-07-03T00:00:00Z") 
}

这对我很有帮助。在完整的上下文中,以下命令获取所有记录,其中dt日期字段的日期为2013-10-01(YYYY-MM-DD)Zulu:

db.mycollection.find({ "dt" : { "$gte" : ISODate("2013-10-01T00:00:00Z"), "$lt" : ISODate("2013-10-02T00:00:00Z") }})

2
我遇到了一个“ISODate未定义”的错误。我无法解决这个问题。 - Batu
1
在使用pymongo的Python中,datetime.datetime等同于ISODate - jtbr
@jtbr 不完全正确。ISODate("2014-07-02T00:00:00Z") 的等效代码是 datetime.datetime.strptime("2014-07-02T00:00:00Z", "%Y-%m-%dT%H:%M:%SZ").isoformat() - Skippy le Grand Gourou

18

试试这个:

{ "dt" : { "$gte" : ISODate("2013-10-01") } }

6
我正在使用Robomongo作为MongoDB客户端GUI,以下内容适用于我:
db.collectionName.find({"columnWithDateTime" : {
$lt:new ISODate("2016-02-28T00:00:00.000Z")}})

在应用程序方面,我正在使用基于Node.js的MongoDB驱动程序(v1.4.3),应用程序在UI中使用日期选择器,日期格式为YYYY-mm-dd,然后将其附加到默认时间00:00:00,并提供给 new Date()构造函数,然后提供给MongoDB条件对象。我认为驱动程序将日期转换为ISO日期,查询然后起作用并提供所需的输出,但是相同的 new Date()构造函数不能在Robo Mongo上工作或显示相同的输出,这很奇怪,因为我使用Robomongo来交叉检查我的条件对象。
而默认的cli mongoshell可以很好地处理 ISODate new Date()

2
谢谢你的建议,Robomongo比Mongo Compass好多了。 - Alex

5
在严格模式下的JSON格式中,您需要保持顺序不变:
{
    "dt": {
        "$gte": {
            "$date": "2013-10-01T00:00:00.000Z"
        }
    }
}

唯一有效的方法是在mlab.com上定义我的搜索查询。


运行查询时出错。原因:(invalid_operator)无效的操作符:$date。 - saber tabatabaee yazdi

3

这是我的文档

"_id" : ObjectId("590173023c488e9a48e903d6"),
    "updatedAt" : ISODate("2017-04-27T04:26:42.709Z"),
    "createdAt" : ISODate("2017-04-27T04:26:42.709Z"),
    "flightId" : "590170f97cb84116075e2680",

 "_id" : ObjectId("590173023c488e9a48e903d6"),
        "updatedAt" : ISODate("2017-04-28T03:26:42.609Z"),
        "createdAt" : ISODate("2017-04-28T03:26:42.609Z"),
        "flightId" : "590170f97cb84116075e2680",

现在我想找到每27个日期的文档。所以我使用了以下方法...

 > db.users.find({createdAt:{"$gte":ISODate("2017-04-27T00:00:00Z"),"$lt":ISODate("2017-04-28T00:00:00Z") }}).count()

result:1

这对我有效。


3

new Date() 包裹它:

{ "dt" : { "$lt" : new Date("2012-01-01T15:00:00.000Z") } }

3

虽然这是一个旧问题,但仍然是谷歌搜索结果的首要选项,因此我在这里发布它,以便将来更容易找到...

使用Mongo 4.2和aggregate()函数:

db.collection.aggregate(
    [
     { $match: { "end_time": { "$gt": ISODate("2020-01-01T00:00:00.000Z")  } } },
     { $project: {
          "end_day": { $dateFromParts: { 'year' : {$year:"$end_time"}, 'month' : {$month:"$end_time"}, 'day': {$dayOfMonth:"$end_time"}, 'hour' : 0  } }
     }}, 
     {$group:{
        _id:   "$end_day",
        "count":{$sum:1},
    }}
   ]
)

这个将日期作为分组变量,有时最好将其作为组成部分来处理。

2
在MongoDB shell中:
db.getCollection('sensorevents').find({from:{$gt: new ISODate('2015-08-30 16:50:24.481Z')}})

在我的nodeJS代码中(使用Mongoose)
    SensorEvent.Model.find( {
        from: { $gt: new Date( SensorEventListener.lastSeenSensorFrom ) }
    } )

我正在查询我的传感器事件集合,以返回“from”字段大于给定日期的值。

4
欢迎来到 Stack Overflow!请只发布回答问题的内容,不要添加额外的内容,例如“这是我的第一篇帖子”之类的内容。请将 Stack Overflow 视为维基百科,而不是留言板。 - durron597

0

虽然我将其与 AWS DocumentDB 进行了测试(它应该兼容 Mongo 4),但我在没有使用 DateISODate 的情况下也能正常工作:

db.collection_name.find({"an_iso_date_field": {$lte: "2021-02-04T03:42:00Z"}})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接