MongoDB - 根据日期返回查询结果

333
我在mongodb中有这样的数据
{ 
    "latitude" : "", 
    "longitude" : "", 
    "course" : "", 
    "battery" : "0", 
    "imei" : "0", 
    "altitude" : "F:3.82V", 
    "mcc" : "07", 
    "mnc" : "007B", 
    "lac" : "2A83", 
    "_id" : ObjectId("4f0eb2c406ab6a9d4d000003"), 
    "createdAt" : ISODate("2012-01-12T20:15:31Z") 
}

如何查询 db.gpsdatas.find({'createdAt': ??这里填什么??}),以便从数据库中将上述数据结果返回给我?

1
提到你使用的是哪个Node.js库会更有效,但根据示例看来似乎是mongoosejs。 - Grimnoff
12个回答

604

你可能想要进行范围查询,比如获取所有在特定日期之后创建的项目:

db.gpsdatas.find({"createdAt" : { $gte : new ISODate("2012-01-12T20:15:31Z") }});

我正在使用$gte(大于或等于),因为通常用于仅包含日期的查询,其中时间组件为00:00:00。

如果您确实想要查找与另一个日期相等的日期,则语法应该是

db.gpsdatas.find({"createdAt" : new ISODate("2012-01-12T20:15:31Z") });

14
啊哈 :) 我原以为你在使用Mongo控制台。在那里,ISODate是js日期对象的包装器。尝试类似于"createdAt" : new Date("2010-01-01")的东西。但是由于某种原因,在Mongo控制台中这段代码(针对版本2.0.2)不起作用。 - mnemosyn
日期初始化可以使用斜杠而不是破折号吗?像这样: new Date("2010/01/01"); - Victor S

33

我刚在Mongo v3.2.3中使用Node v0.12.7和v4.4.4实现了类似的东西,并使用了:

{ $gte: new Date(dateVar).toISOString() }

我传递了一个ISO日期(例如2016-04-22T00:00:00Z),这对于带或不带toISOString函数的.find()查询有效。但是,在使用.aggregate()$match查询时,它不喜欢使用toISOString函数!


".toISOString()"非常有帮助。 - Howard Lee
使用Mongoose 5,无需使用.toISOString()即可正常工作。 - DBencz
至少目前来看,它与MongoDB(例如Atlas)不兼容...语法错误。使用IsoDate()则可以正常工作。 - Fabien Haddadi
你应该避免将一个日期值与一个字符串进行比较。最好是将一个日期值与另一个日期进行比较,因此{ $gte: new Date(dateVar) }会更好。 - undefined

21

如果你想在那天的任何地方获得物品,你需要比较两个日期。

你可以通过第一个日期创建两个日期,如下所示,以获得当天的开始和结束时间。

var startDate = new Date(); // this is the starting date that looks like ISODate("2014-10-03T04:00:00.188Z")

startDate.setSeconds(0);
startDate.setHours(0);
startDate.setMinutes(0);

var dateMidnight = new Date(startDate);
dateMidnight.setHours(23);
dateMidnight.setMinutes(59);
dateMidnight.setSeconds(59);

### MONGO QUERY

var query = {
        inserted_at: {
                    $gt:morning,
                    $lt:dateScrapedMidnight
        }
};

//MORNING: Sun Oct 12 2014 00:00:00 GMT-0400 (EDT)
//MIDNIGHT: Sun Oct 12 2014 23:59:59 GMT-0400 (EDT)

我想指出你在这里失去了最后一秒钟,你真正想要的是 var dateNextDate = startDate.AddDays(1) 然后对那个日期进行 lt。 - Traderhut Games

16

如果您想获取过去5分钟内的所有新内容,您需要进行一些计算,但这并不困难...

首先,在您想要匹配的属性上创建索引(包括排序方向-1表示降序,1表示升序)

db.things.createIndex({ createdAt: -1 }) // descending order on .createdAt

然后查询最近5分钟(60秒*5分钟)创建的文件...因为JavaScript的 .getTime() 返回的是毫秒,所以您需要在将其用作 new Date() 构造函数的输入之前将其乘以1000。

db.things.find({
        createdAt: {
            $gte: new Date(new Date().getTime()-60*5*1000).toISOString()
         }
     })
     .count()
new Date(new Date().getTime()-60*5*1000).toISOString() 的解释如下:
首先,我们计算“5分钟前”:
1. new Date().getTime() 给出当前时间的毫秒数。 2. 我们想从中减去 5 分钟(以毫秒为单位):5*60*1000——我只是乘以 60 秒,这样很容易改变。如果我想要 2 小时(120 分钟),我只需将 5 更改为 120。 3. new Date().getTime()-60*5*1000 给出了 1484383878676(5 分钟前的毫秒数)。
现在我们需要将其馈入新的 new Date() 构造函数中,以获得 MongoDB 时间戳所需的 ISO 字符串格式。
1. { $gte: new Date(resultFromAbove).toISOString() }(mongodb .find() 查询) 2. 由于我们不能使用变量,因此我们一次性完成所有操作:new Date(new Date().getTime()-60*5*1000) 3. 然后转换为 ISO 字符串:.toISOString() 4. new Date(new Date().getTime()-60*5*1000).toISOString() 给出了 2017-01-14T08:53:17.586Z 当然,如果您正在使用 node-mongodb-native 驱动程序,则使用变量会更容易些,但如果我要检查某些内容,通常会在 mongo shell 中使用此方法。

4
我认为你可以使用 Date.now() 替代 new Date().getTime() - Béranger

13

按照特定日期查找:

db.getCollection('CollectionName').find({"DepartureDate" : new ISODate("2019-06-21T00:00:00.000Z")})

查找大于等于 gte 或小于 lt 的值:

db.getCollection('CollectionName').find({"DepartureDate" : { $gte : new ISODate("2019-06-11T00:00:00.000Z") }})

按范围查找:

db.getCollection('CollectionName').find({ 
    "DepartureDate": { 
        $lt: new Date(), 
        $gte: new Date(new Date().setDate(new Date().getDate()-15))
      } 
    })

1
提示:对于不等式,“大于”、“小于”,如果您真正想要的是午夜,则无需描述HH:MM:SS和时区:您可以省略“T00:00:00.000Z”。 - Fabien Haddadi
当然没问题! - Hamit YILDIRIM

6

你也可以尝试:

{
    "dateProp": { $gt: new Date('06/15/2016').getTime() }
}

2
如果您正在使用Mongoose,
try {
  const data = await GPSDatas.aggregate([
    {
      $match: { createdAt : { $gt: new Date() }
    },
    {
      $sort: { createdAt: 1 }
    }
  ])
  console.log(data)

} catch(error) {
    console.log(error)
}

1
个人而言,我更倾向于避免使用客户端的JavaScript处理或第三方库,如moment.js,以避免客户端和服务器端之间时区处理的不一致。
1. 基于范围的查询
db.collection.find({
  "createdAt": {
    $gte: ISODate("2012-01-12T00:00:00Z"),
    $lt: ISODate("2012-01-13T00:00:00Z")
  }
})

使用$dateFromParts构建日期范围
db.collection.find({
  $expr: {
    $gte: [
      "$createdAt",
      {
        "$dateFromParts": {
          "year": 2012,
          "month": 1,
          "day": 12
        }
      }
    ]
  }
})

获取日期差异范围(例如,当前日期之前15年)
db.collection.find({
  $expr: {
    $gte: [
      "$createdAt",
      {
        "$dateSubtract": {
          "startDate": "$$NOW",
          "unit": "year",
          "amount": 15
        }
      }
    ]
  }
})

0
如果您正在使用MongoDB聚合功能,那么以下是代码:
  1. 在这里,我将日期从dd/mm/yyyy转换为ISO日期(因为日期在数据库中以ISO日期格式存储)

const dateToIso=(from, to)=>{
    return {
        fromIsoDate: moment(from,"DD/MM/YYYY").toISOString(),
        toIsoDate: moment(to,"DD/MM/YYYY").add(1,'days').toISOString()
    }
}

最后,使用MongoDB聚合这些值:

{
                $match:{
                    $and:[
                        {
                            createdAt:{
                                $lte: new Date(toIsoDate)
                            }
                        },
                        {
                            createdAt:{
                                $gte: new Date(fromIsoDate)
                            }
                        },
                        
                    ]
                }
            },


1
你应该避免将一个日期值与一个字符串进行比较。最好使用moment(from, "DD/MM/YYYY").toDate(),然后你可以将日期值与日期进行比较。 - undefined

0
每当你需要处理日期值时,我建议使用第三方的日期库,比如moments.jsLuxonDay.js
  {
    $match: {
      createdAt: { $gte: DateTime.fromISO(date).toJSDate() }
    }
  }

或者 createdAt: { $gte: moment().toDate() } 对于普通的 Date 值,没有任何区别,即您可以使用原生的 new Date(...)ISODate(...)。然而,当您需要处理时区或其他数学运算(例如 beginOf('hour')endOf('week')add({days:7,months:1}) 等),这些库比原生的 JavaScript Date 对象更容易使用和更可预测。

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