文档菜单
文档首页
/
MongoDB 手册
/ / /

$dateSubtract (聚合)

本页内容

  • 定义
  • 行为
  • 示例
$dateSubtract

版本5.0.

减少一个Date()对象,通过指定的数量单位。

表达式$dateSubtract表达式具有以下语法

{
$dateSubtract: {
startDate: <Expression>,
unit: <Expression>,
amount: <Expression>,
timezone: <tzExpression>
}
}

返回一个Date()startDate可以是任何解析为日期、时间戳或ObjectId类型的表达式。无论使用哪种数据类型作为输入,返回的值都将是一个Date()对象。

字段
必需/可选
描述
startDate
必需
减法操作的起始日期,以UTC表示。startDate可以是任何解析为日期、时间戳或ObjectId的表达式。
unit
必需

用于测量从startDate减去的时间量的单位。unit是一个解析为以下字符串之一的表达式

  • 季度

  • 小时

  • 分钟

  • 毫秒

amount
必需
startDate减去的单位数量。该amount是一个表达式,其结果为整数或长整型。如果该值可以无精度损失地转换为长整型,则amount也可以解析为整数小数或双精度浮点数。
时区
可选

执行操作的时区。<tzExpression>必须是一个有效的表达式,其结果为格式化为Olson时区标识符的字符串或UTC偏移量。如果没有提供timezone,则结果将显示为UTC

格式
示例
Olson时区标识符
"America/New_York"
"Europe/London"
"GMT"
UTC偏移量
+/-[hh]:[mm], e.g. "+04:45"
+/-[hh][mm], e.g. "-0530"
+/-[hh], e.g. "+03"

有关表达式和类型的更多信息,请参阅表达式运算符BSON类型

MongoDB遵循数据库的通用使用规则,以UTC时间处理时间。`dateSubtract`表达式始终以UTC的`startDate`作为参数,并以UTC返回结果。如果指定了`timezone`,则将使用指定的`timezone`进行计算。时区在涉及夏令时(DST)的计算中尤为重要。

如果`unit`是一个`month`或更大,则操作会调整到最后一天。例如,在三月的最后一天减去一个月,就显示了“月底调整”。

{
$dateSubtract:
{
startDate: ISODate("2021-03-31T12:10:05Z"),
unit: "month",
amount: 1
}
}

请注意,返回的日期`ISODate("2021-02-28T12:10:05Z")`是28日而不是31日,因为2月的天数少于3月。

当在``字段中使用Olson时区标识符时,MongoDB会应用指定时区的夏令时偏移量(如果适用)。

例如,考虑一个包含以下文档的`sales`集合

{
"_id" : 1,
"item" : "abc",
"price" : 20,
"quantity" : 5,
"date" : ISODate("2017-05-20T10:24:51.303Z")
}

以下聚合演示了MongoDB如何处理Olson时区标识符的DST偏移量。示例使用$hour$minute运算符来返回date字段的相应部分

db.sales.aggregate([
{
$project: {
"nycHour": {
$hour: { date: "$date", timezone: "-05:00" }
},
"nycMinute": {
$minute: { date: "$date", timezone: "-05:00" }
},
"gmtHour": {
$hour: { date: "$date", timezone: "GMT" }
},
"gmtMinute": {
$minute: { date: "$date", timezone: "GMT" } },
"nycOlsonHour": {
$hour: { date: "$date", timezone: "America/New_York" }
},
"nycOlsonMinute": {
$minute: { date: "$date", timezone: "America/New_York" }
}
}
}])

该操作返回以下结果

{
"_id": 1,
"nycHour" : 5,
"nycMinute" : 24,
"gmtHour" : 10,
"gmtMinute" : 24,
"nycOlsonHour" : 6,
"nycOlsonMinute" : 24
}

考虑一个类似以下系统连接时间的集合

db.connectionTime.insertMany(
[
{
custId: 457,
login: ISODate("2020-12-25T19:04:00"),
logout: ISODate("2020-12-28T09:04:00")
},
{
custId: 457,
login: ISODate("2021-01-27T05:12:00"),
logout: ISODate("2021-01-28T13:05:00")
},
{
custId: 458,
login: ISODate("2021-01-22T06:27:00"),
logout: ISODate("2021-01-31T11:00:00")
},
{
custId: 459,
login: ISODate("2021-02-14T20:14:00"),
logout: ISODate("2021-02-17T16:05:00")
},
{
custId: 460,
login: ISODate("2021-02-26T02:44:00"),
logout: ISODate("2021-02-18T14:13:00")
}
]
)

由于服务问题,您需要从2021年1月的每个登出时间中减去3小时。您可以在聚合管道中使用$dateSubtract来递减logoutTime

db.connectionTime.aggregate(
[
{
$match:
{
$expr:
{
$eq:
[
{ $year: "$logout" },
2021
]
},
$expr:
{
$eq:
[
{ $month: "$logout" },
1
]
}
}
},
{
$project:
{
logoutTime:
{
$dateSubtract:
{
startDate: "$logout",
unit: "hour",
amount: 3
}
}
}
},
{
$merge: "connectionTime"
}
]
)

$match阶段进行了两个类似的比较。首先,$year$month运算符分别从logoutTime日期对象中提取年份和月份。然后检查月份和年份是否与选择目标匹配。由于“January”编码为“1”,当年份和月份等于“2021”和“1”时,$expr为真($eq)。

$project阶段使用$dateSubtract从每个选定文档的logoutTime中减去3小时。

最后,$merge 阶段更新集合,为修改后的文档写入新的 logoutTime

注意

$out 不同,$merge 阶段仅更新匹配的文档,并保留集合的其余部分。更多详情请见:[与 $merge 对比 $out](#std-label-out-merge-comparison)。

结果文档如下所示

{
"_id" : ObjectId("603dd94b044b995ad331c0b5"),
"custId" : 457,
"login" : ISODate("2020-12-25T19:04:00Z"),
"logout" : ISODate("2020-12-28T09:04:00Z")
}
{
"_id" : ObjectId("603dd94b044b995ad331c0b6"),
"custId" : 457,
"login" : ISODate("2021-01-27T05:12:00Z"),
"logout" : ISODate("2021-01-28T13:05:00Z"),
"logoutTime" : ISODate("2021-01-28T10:05:00Z")
}
{
"_id" : ObjectId("603dd94b044b995ad331c0b7"),
"custId" : 458,
"login" : ISODate("2021-01-22T06:27:00Z"),
"logout" : ISODate("2021-01-31T11:00:00Z"),
"logoutTime" : ISODate("2021-01-31T08:00:00Z")
}
{
"_id" : ObjectId("603dd94b044b995ad331c0b8"),
"custId" : 459,
"login" : ISODate("2021-02-14T20:14:00Z"),
"logout" : ISODate("2021-02-17T16:05:00Z")
}
{
"_id" : ObjectId("603dd94b044b995ad331c0b9"),
"custId" : 460,
"login" : ISODate("2021-02-26T02:44:00Z"),
"logout" : ISODate("2021-02-18T14:13:00Z")
}

您想向在过去一周内使用过您服务的客户发送调查问卷。使用 $dateSubtract 表达式可以创建一个相对于查询执行时间的范围筛选。

db.connectionTime.aggregate(
[
{
$match:
{
$expr:
{
$gt:
[
"$logoutTime",
{
$dateSubtract:
{
startDate: "$$NOW",
unit: "week",
amount: 1
}
}
]
}
}
},
{
$project:
{
_id: 0,
custId: 1,
loggedOut:
{
$dateToString:
{
format: "%Y-%m-%d",
date: "$logoutTime"
}
}
}
}
]
)

内置的聚合变量 $$NOW 返回当前日期时间,格式为 ISODate。在 $match 阶段中,使用 $$NOW 的值来获取今天的日期。然后,使用比较表达式 ($expr) 通过大于 ($gt) 和 $dateSubtract 来筛选集合,以匹配在过去一周内有 logoutTime 的文档。

$project 阶段使用 $dateToString 表达式将日期转换为更易读的格式。如果不进行转换,MongoDB 会以 ISODate 格式返回日期,并假设时区为 UTC。

输出显示过去一周内有两位客户已登出。

{ "custId" : 459, "loggedOut" : "2021-02-17" }
{ "custId" : 460, "loggedOut" : "2021-02-18" }

所有日期都存储为UTC时间。当指定了时区时,$dateSubtract使用本地时间进行计算。结果以UTC显示。

您有来自几个时区的客户,并想查看如果按或按小时计费,夏令时可能会对您的计费周期产生什么影响。

创建此连接时间集合

db.billing.insertMany(
[
{
location: "America/New_York",
login: ISODate("2021-03-14T10:00:00-0500"),
logout: ISODate("2021-03-14T18:00:00-0500")
},
{
location: "America/Mexico_City",
login: ISODate("2021-03-14T10:00:00-00:00"),
logout: ISODate("2021-03-15T08:00:00-0500")
}
]
)

首先从每个文档中的登录日期中减去1天,然后减去24小时。

db.billing.aggregate(
[
{
$project:
{
_id: 0,
location: 1,
start:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date: "$login"
}
},
days:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateSubtract:
{
startDate: "$login",
unit: "day",
amount: 1,
timezone: "$location"
}
}
}
},
hours:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateSubtract:
{
startDate: "$login",
unit: "hour",
amount: 24,
timezone: "$location"
}
}
}
},
startTZInfo:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date: "$login",
timezone: "$location"
}
},
daysTZInfo:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateSubtract:
{
startDate: "$login",
unit: "day",
amount: 1,
timezone: "$location"
}
},
timezone: "$location"
}
},
hoursTZInfo:
{
$dateToString:
{
format: "%Y-%m-%d %H:%M",
date:
{
$dateSubtract:
{
startDate: "$login",
unit: "hour",
amount: 24,
timezone: "$location"
}
},
timezone: "$location"
}
},
}
}
]
).pretty()

$dateToString表达式重新格式化输出以提高可读性。结果在此总结

字段
纽约
墨西哥城
开始
2021-03-14 15:00
2021-03-14 15:00
开始,时区信息
2021-03-14 11:00
2021-03-14 04:00
1天
2021-03-13 16:00
2021-03-13 15:00
1天,时区信息
2021-03-13 11:00
2021-03-13 09:00
24小时
2021-03-13 15:00
2021-03-13 15:00
24小时,时区信息
2021-03-13 10:00
2021-03-13 09:00

图表突出了几个重点

  • 未格式化的日期以UTC返回。纽约的$login是UTC -5,但是开始天数小时数行显示的是UTC时间。

  • 3月14日是纽约夏令时的开始,但不是墨西哥。当位置切换到夏令时并从一天跨越到下一天时,计算时间会进行调整。

  • 夏令时改变的是的长度,而不是小时。没有针对小时的夏令时更改。只有当测量单位或更大,并且计算跨越指定时区的时钟变化时,才会调整夏令时。

提示

另请参阅

返回

$dateFromString

本页内容