聚合截断日期函数?
Aggregate trunc date function?
我以前用过一堆 SQL 数据库;像 Postgres 和 BigQuery,它们有日期截断功能(例如:date_trunc
or TIMESTAMP_TRUNC
)。
不知道mongodb有没有DATE_TRUNC功能?
我找到了 $trunc
运算符,但它仅适用于数字。
我想要一个 DATE_TRUNC 函数将给定日期(其他 SQL 数据库中的时间戳类型)截断到特定边界,例如年初、月初、小时开始,可能可以通过获取年、月、日、小时来组成一个新的日期。
有人有解决方法吗?特别是对于 WEEK 的开始时刻和 ISOWEEK 的开始,有没有人有好的解决方法?
可以通过对日期或时间戳字段进行运算来获得 ISO 周的开始,这里的周开始是 Monday
(1),周结束是 Sunday
(7)
db.dd.aggregate(
[
{
$addFields : {
startOfWeek : 1, // Monday
currentDayOfWeek : {$dayOfWeek : "$date"},
daysToMinus : { $subtract : [{$dayOfWeek : "$date"} , 1] },
startOfThisWeek : { $subtract : [ "$date", {$multiply : [{ $subtract : [{$dayOfWeek : "$date"} , 1 ] }, 24, 60, 60, 1000 ] } ] }
}
}
]
).pretty()
文件
> db.dd.find()
{ "_id" : ObjectId("5a62e2697702c6be61d672f4"), "date" : ISODate("2018-01-20T06:32:09.157Z") }
一周开始
{
"_id" : ObjectId("5a62e2697702c6be61d672f4"),
"date" : ISODate("2018-01-20T06:32:09.157Z"),
"startOfWeek" : 1,
"currentDayOfWeek" : 7,
"daysToMinus" : 6,
"startOfThisWeek" : ISODate("2018-01-14T06:32:09.157Z")
}
>
可以使用 $dateFromParts 函数将日期截断为等周:
例如
db.dd.aggregate(
{
$dateFromParts: {
isoWeekYear: { $isoWeekYear: "$date" },
isoWeek: { $isoWeek: "$date" }
}
}
)
对于Fri, 22 Jun 2018 20:46:50 UTC +00:00
它returns Fri, 18 Jun 2018 00:00:00 UTC +00:00
。
要截断到小时、天、月等,使用 $dateFromString
和 $dateToString
更容易。以下示例将日期截断为小时:
db.dd.aggregate(
{
$dateFromString: {
dateString: {
$dateToString: {
format: '%Y-%m-%dT%H:00:00+00:00',
date: '$date'
}
}
}
}
)
可以合并$dateToParts and $dateFromParts
年、月、日、小时, 分钟:
db.getCollection("data").aggregate([
{"$addFields": {
"dateVarFull": {"$dateToParts": {date: {"$toDate" : "2020-08-27T13:00:00Z"}}}
}},
{"$addFields": {
"dateVarTrunc": { "$dateFromParts": {
'year': "$dateVarFull.year",
'month': "$dateVarFull.month",
'day': "$dateVarFull.day"
}}
}}
])
结果:
{
"dateVarFull" : {
"year" : NumberInt(2020),
"month" : NumberInt(8),
"day" : NumberInt(27),
"hour" : NumberInt(13),
"minute" : NumberInt(0),
"second" : NumberInt(0),
"millisecond" : NumberInt(0)
},
"dateVarTrunc" : ISODate("2020-08-27T00:00:00.000+0000")
}
对于week trunc 使用iso8601: true
参数:
db.getCollection("data").aggregate([
{"$addFields": {
"dateVarFull": {
"$dateToParts": {
date: {"$toDate" : "2020-08-27T13:00:00Z"},
iso8601: true
}
}
}},
{"$addFields": {
"dateVarTrunc": { "$dateFromParts": {
'isoWeekYear': "$dateVarFull.isoWeekYear",
'isoWeek': "$dateVarFull.isoWeek",
'isoDayOfWeek': 1
}}
}}
])
结果:
{
"dateVarFull" : {
"isoWeekYear" : NumberInt(2020),
"isoWeek" : NumberInt(35),
"isoDayOfWeek" : NumberInt(4),
"hour" : NumberInt(13),
"minute" : NumberInt(0),
"second" : NumberInt(0),
"millisecond" : NumberInt(0)
},
"dateVarTrunc" : ISODate("2020-08-24T00:00:00.000+0000")
}
从 Mongo 5
开始,您的愿望已通过 $dateTrunc
运算符实现。
例如,将日期截断为年份:
// { date: ISODate("2021-12-05T13:20:56Z") }
// { date: ISODate("2019-04-27T05:00:32Z") }
db.collection.aggregate([
{ $project: { year: { $dateTrunc: { date: "$date", unit: "year" } } } }
])
// { year: ISODate("2021-01-01T00:00:00Z") }
// { year: ISODate("2019-01-01T00:00:00Z") }
您可以使用 unit
参数在不同级别的单位(年、月、日、小时...甚至季度)进行截断。对于不同单位倍数的给定单位(例如 3 年,6 个月,...),使用 binSize
参数。
您还可以指定周开始的日期:
// { date: ISODate("2021-12-05T13:20:56Z") } <= Sunday
// { date: ISODate("2021-12-06T05:00:32Z") } <= Monday
db.collection.aggregate([
{ $project: {
week: { $dateTrunc: { date: "$date", unit: "week", startOfWeek: "monday" } }
}}
])
// { week: ISODate("2021-11-29T00:00:00Z") }
// { week: ISODate("2021-12-06T00:00:00Z") }
我以前用过一堆 SQL 数据库;像 Postgres 和 BigQuery,它们有日期截断功能(例如:date_trunc
or TIMESTAMP_TRUNC
)。
不知道mongodb有没有DATE_TRUNC功能?
我找到了 $trunc
运算符,但它仅适用于数字。
我想要一个 DATE_TRUNC 函数将给定日期(其他 SQL 数据库中的时间戳类型)截断到特定边界,例如年初、月初、小时开始,可能可以通过获取年、月、日、小时来组成一个新的日期。
有人有解决方法吗?特别是对于 WEEK 的开始时刻和 ISOWEEK 的开始,有没有人有好的解决方法?
可以通过对日期或时间戳字段进行运算来获得 ISO 周的开始,这里的周开始是 Monday
(1),周结束是 Sunday
(7)
db.dd.aggregate(
[
{
$addFields : {
startOfWeek : 1, // Monday
currentDayOfWeek : {$dayOfWeek : "$date"},
daysToMinus : { $subtract : [{$dayOfWeek : "$date"} , 1] },
startOfThisWeek : { $subtract : [ "$date", {$multiply : [{ $subtract : [{$dayOfWeek : "$date"} , 1 ] }, 24, 60, 60, 1000 ] } ] }
}
}
]
).pretty()
文件
> db.dd.find()
{ "_id" : ObjectId("5a62e2697702c6be61d672f4"), "date" : ISODate("2018-01-20T06:32:09.157Z") }
一周开始
{
"_id" : ObjectId("5a62e2697702c6be61d672f4"),
"date" : ISODate("2018-01-20T06:32:09.157Z"),
"startOfWeek" : 1,
"currentDayOfWeek" : 7,
"daysToMinus" : 6,
"startOfThisWeek" : ISODate("2018-01-14T06:32:09.157Z")
}
>
可以使用 $dateFromParts 函数将日期截断为等周:
例如
db.dd.aggregate(
{
$dateFromParts: {
isoWeekYear: { $isoWeekYear: "$date" },
isoWeek: { $isoWeek: "$date" }
}
}
)
对于Fri, 22 Jun 2018 20:46:50 UTC +00:00
它returns Fri, 18 Jun 2018 00:00:00 UTC +00:00
。
要截断到小时、天、月等,使用 $dateFromString
和 $dateToString
更容易。以下示例将日期截断为小时:
db.dd.aggregate(
{
$dateFromString: {
dateString: {
$dateToString: {
format: '%Y-%m-%dT%H:00:00+00:00',
date: '$date'
}
}
}
}
)
可以合并$dateToParts and $dateFromParts
年、月、日、小时, 分钟:
db.getCollection("data").aggregate([
{"$addFields": {
"dateVarFull": {"$dateToParts": {date: {"$toDate" : "2020-08-27T13:00:00Z"}}}
}},
{"$addFields": {
"dateVarTrunc": { "$dateFromParts": {
'year': "$dateVarFull.year",
'month': "$dateVarFull.month",
'day': "$dateVarFull.day"
}}
}}
])
结果:
{
"dateVarFull" : {
"year" : NumberInt(2020),
"month" : NumberInt(8),
"day" : NumberInt(27),
"hour" : NumberInt(13),
"minute" : NumberInt(0),
"second" : NumberInt(0),
"millisecond" : NumberInt(0)
},
"dateVarTrunc" : ISODate("2020-08-27T00:00:00.000+0000")
}
对于week trunc 使用iso8601: true
参数:
db.getCollection("data").aggregate([
{"$addFields": {
"dateVarFull": {
"$dateToParts": {
date: {"$toDate" : "2020-08-27T13:00:00Z"},
iso8601: true
}
}
}},
{"$addFields": {
"dateVarTrunc": { "$dateFromParts": {
'isoWeekYear': "$dateVarFull.isoWeekYear",
'isoWeek': "$dateVarFull.isoWeek",
'isoDayOfWeek': 1
}}
}}
])
结果:
{
"dateVarFull" : {
"isoWeekYear" : NumberInt(2020),
"isoWeek" : NumberInt(35),
"isoDayOfWeek" : NumberInt(4),
"hour" : NumberInt(13),
"minute" : NumberInt(0),
"second" : NumberInt(0),
"millisecond" : NumberInt(0)
},
"dateVarTrunc" : ISODate("2020-08-24T00:00:00.000+0000")
}
从 Mongo 5
开始,您的愿望已通过 $dateTrunc
运算符实现。
例如,将日期截断为年份:
// { date: ISODate("2021-12-05T13:20:56Z") }
// { date: ISODate("2019-04-27T05:00:32Z") }
db.collection.aggregate([
{ $project: { year: { $dateTrunc: { date: "$date", unit: "year" } } } }
])
// { year: ISODate("2021-01-01T00:00:00Z") }
// { year: ISODate("2019-01-01T00:00:00Z") }
您可以使用 unit
参数在不同级别的单位(年、月、日、小时...甚至季度)进行截断。对于不同单位倍数的给定单位(例如 3 年,6 个月,...),使用 binSize
参数。
您还可以指定周开始的日期:
// { date: ISODate("2021-12-05T13:20:56Z") } <= Sunday
// { date: ISODate("2021-12-06T05:00:32Z") } <= Monday
db.collection.aggregate([
{ $project: {
week: { $dateTrunc: { date: "$date", unit: "week", startOfWeek: "monday" } }
}}
])
// { week: ISODate("2021-11-29T00:00:00Z") }
// { week: ISODate("2021-12-06T00:00:00Z") }