我试图按小时聚合MongoDB colloection中的记录,并且需要将存储为timestamp(毫秒)的日期转换为ISODate,以便我可以使用聚合框架的内置日期运算符($ hour,$ month)等等。)
记录存储为
{
"data" : { "UserId" : "abc", "ProjId" : "xyz"},
"time" : NumberLong("1395140780706"),
"_id" : ObjectId("532828ac338ed9c33aa8eca7")
}
我正在尝试使用以下类型的聚合查询:
db.events.aggregate(
{
$match : {
"time" : { $gte : 1395186209804, $lte : 1395192902825 }
}
},
{
$project : {
_id : "$_id",
dt : {$concat : (Date("$time")).toString()} // need to project as ISODate
}
},
// process records further in $project or $group clause
)
产生以下形式的结果:
{
"result" : [
{
"_id" : ObjectId("5328da21fd207d9c3567d3ec"),
"dt" : "Fri Mar 21 2014 17:35:46 GMT-0400 (EDT)"
},
{
"_id" : ObjectId("5328da21fd207d9c3567d3ed"),
"dt" : "Fri Mar 21 2014 17:35:46 GMT-0400 (EDT)"
},
...
}
我想从日期中提取小时,日,月和年,但由于时间是作为字符串预测的,因此我无法使用聚合框架的内置日期运算符($ hour等)。
如何将时间从毫秒转换为ISO日期,以执行以下操作:
db.events.aggregate(
{
$match : {
"time" : { $gte : 1395186209804, $lte : 1395192902825 }
}
},
{
$project : {
_id : "$_id",
dt : <ISO date from "$time">
}
},
{
$project : {
_id : "$_id",
date : {
hour : {$hour : "$dt"}
}
}
}
)
答案 0 :(得分:31)
实际上,有可能,诀窍是使用类似于下面的语法将您的毫秒时间添加到零毫秒Date()对象:
dt : {$add: [new Date(0), "$time"]}
我从上面修改了你的聚合以产生结果:
db.events.aggregate(
{
$project : {
_id : "$_id",
dt : {$add: [new Date(0), "$time"]}
}
},
{
$project : {
_id : "$_id",
date : {
hour : {$hour : "$dt"}
}
}
}
);
结果是(您的样本数据有一个条目):
{
"result": [
{
"_id": ObjectId("532828ac338ed9c33aa8eca7"),
"date": {
"hour": 11
}
}
],
"ok": 1
}
答案 1 :(得分:7)
我认为没有办法做到这一点。因为聚合框架是用本机代码编写的。没有使用V8引擎。因此,JavaScript的所有内容都无法在框架内工作(这也是聚合框架运行速度更快的原因)。
Map / Reduce是一种解决这个问题的方法,但聚合框架肯定会有更好的性能。
关于地图/降低效果,请阅读this thread。
另一种解决方法是获得一个&#34; raw&#34;聚合框架的结果,将其放入JSON数组中。然后通过运行JavaScript进行转换。有点像:
var results = db.events.aggregate(...);
reasult.forEach(function(data) {
data.date = new Date(data.dateInMillionSeconds);
// date is now stored in the "date" property
}
答案 2 :(得分:2)
要返回有效的BSON日期,您只需要一个小日期&#34;数学&#34;使用$add
运算符。您需要将new Date(0)
添加到时间戳。 new Date(0)
表示自Unix纪元(1970年1月1日)以来的毫秒数,是new Date("1970-01-01")
的简写。
db.events.aggregate([
{ "$match": { "time": { "$gte" : 1395136209804, "$lte" : 1395192902825 } } },
{ "$project": {
"hour": { "$hour": { "$add": [ new Date(0), "$time" ] } },
"day": { "$dayOfMonth": { "$add": [ new Date(0), "$time" ] } },
"month": { "$month": { "$add": [ new Date(0), "$time" ] } },
"year": { "$year": { "$add": [ new Date(0), "$time" ] } }
}}
])
哪个收益率:
{
"_id" : ObjectId("532828ac338ed9c33aa8eca7"),
"hour" : 11,
"day" : 18,
"month" : 3,
"year" : 2014
}
答案 3 :(得分:0)
如果
,请使用此功能{$add: [new Date(0), "$time"]
}函数返回string type
而不是ISO date type
我使用了所有该选项,但仍然失败,因为我$project
的新约会为string type
提供'2000-11-2:xxxxxxx'
而不是date type
,如ISO('2000-11-2:xxxxxxx')
与我有同样问题的人使用这个。
db.events.aggregate(
{
$project : {
_id : "$_id",
dt : {$add: [new Date(0), "$time"]}
}
},
{
$project : {
_id : "$_id",
"year": { $substr: [ "$dt", 0, 4 ] },
"month": { $substr: [ "$dt", 5, 2] },
"day": { $substr: [ "$dt", 8, 2 ] }
}
}
);
结果将是
{ _id: '59f940eaea87453b30f42cf5',
year: '2017',
month: '07',
day: '04'
},
如果您想根据string
subset
取决于group
,您可以根据相同的日期,月份或年份再次{{1}}
答案 4 :(得分:0)
从Mongo 4.0
开始,有一个新的$toDate
聚合运算符,它可以从各种类型转换为日期(在这种情况下是长整型):
// { time: NumberLong("1395140780706") }
db.collection.aggregate({ $set: { time: { $toDate: "$time" } } })
// { time: ISODate("2014-03-18T11:06:20.706Z") }
并节省时间:
// { time: NumberLong("1395140780706") }
db.collection.aggregate({ $project: { hour: { $hour: { $toDate: "$time" } } } })
// { hour: 11 }