$dateSubtract (aggregation)
On this page本页内容
Definition定义
$dateSubtractNew in version 5.0.5.0版新增。Decrements a将Date()object by a specified number of time units.Date()对象递减指定数量的时间单位。The$dateSubtractexpression has the following syntax:$dateSubtract表达式具有以下语法:{
$dateSubtract: {
startDate: <Expression>,
unit: <Expression>,
amount: <Expression>,
timezone: <tzExpression>
}
}Returns a返回Date().Date()。ThestartDatecan be any expression that resolves to type Date, Timestamp or ObjectId.startDate可以是解析为Date、Timestamp或ObjectId类型的任何表达式。No matter which data type is used as input, the value returned will be a无论使用哪种数据类型作为输入,返回的值都将是Date()object.Date()对象。Field字段Required/Optional必需/可选Description描述startDateRequired必要的The beginning date, in UTC, for the subtraction operation.减法运算的开始日期,以UTC为单位。ThestartDatecan be any expression that resolves to a Date, a Timestamp, or an ObjectID.startDate可以是解析为Date、Timestamp或ObjectID的任何表达式。unitRequired必要的The用于测量从unitused to measure theamountof time subtracted from thestartDate.startDate减去的时间amount的unit。Theunitis an expression that resolves to one of the following strings:unit是一个解析为以下字符串之一的表达式:yearquarterweekmonthdayhourminutesecondmillisecond
amountRequired必要的The number of从unitssubtracted from thestartDate.startDate中减去的units数。Theamountis an expression that resolves to an integer or long.amount是一个解析为整数或长的表达式。The如果可以在不损失精度的情况下将amountcan also resolve to an integral decimal and or a double if that value can be converted to a long without loss of precision.amount转换为long,则amount也可以解析为整数小数和/或double。timezoneOptional可选的The timezone to carry out the operation.执行操作的时区。<tzExpression>must be a valid expression that resolves to a string formatted as either an Olson Timezone Identifier必须是一个有效的表达式,该表达式解析为格式为Olson时区标识符or a UTC Offset
.
或UTC偏移
的字符串。
If no如果没有提供timezoneis provided, the result is displayed inUTC.timezone,结果将以UTC显示。Format格式Examples示例Olson Timezone IdentifierOlson时区标识符"America/New_York"
"Europe/London"
"GMT"UTC Offset +/-[hh]:[mm], e.g. "+04:45"
+/-[hh][mm], e.g. "-0530"
+/-[hh], e.g. "+03"For more information on expressions and types see Expressions and BSON Types.有关表达式和类型的详细信息,请参阅表达式和BSON类型。
Behavior行为
Time Measurement时间测量
MongoDB follows prevaling database usage and works with time in UTC. MongoDB遵循普遍使用的数据库,并使用UTC中的时间。The dateSubtract expression always takes a startDate in UTC and returns a result in UTC. dateSubtract表达式总是以UTC为startDate,并以UTC为返回结果。If the 如果指定了timezone is specified, the calculation will be done using the specified timezone. timezone,则将使用指定的timezone进行计算。The timezone is especially important when a calculation involves Daylight Savings Time (DST).当计算涉及夏令时(DST)时,时区尤其重要。
If the 如果unit is a month, or larger the operation adjusts to account for the last day of the month. unit是一个month或更大,则操作会根据该月的最后一天进行调整。Subtracting one 例如,在3月的最后一天减去一个月(month on the last day of March, for example, demonstrates the "last-day-of-the-month" adjustment.month),表示“一个月的最后几天”的调整。
{
   $dateSubtract:
      {
         startDate: ISODate("2021-03-31T12:10:05Z"),
         unit: "month",
         amount: 1
      }
}
Notice that the date returned, 请注意,返回的日期ISODate("2021-02-28T12:10:05Z"), is the 28th and not the 31st since February has fewer days than March.ISODate("2021-02-28T12:10:05Z")是28日,而不是31日,因为2月的天数比3月少。
Time Zone时区
When using an Olson Timezone Identifier in the 当在<timezone> field, MongoDB applies the DST offset if applicable for the specified timezone.<timezone>字段中使用Olson时区标识符时,MongoDB会应用DST偏移量(如果适用于指定时区)。
For example, consider a 例如,考虑具有以下文档的sales collection with the following document:sales集合:
{
   "_id" : 1,
   "item" : "abc",
   "price" : 20,
   "quantity" : 5,
   "date" : ISODate("2017-05-20T10:24:51.303Z")
}
The following aggregation illustrates how MongoDB handles the DST offset for the Olson Timezone Identifier. 下面的聚合说明了MongoDB如何处理Olson时区标识符的DST偏移量。The example uses the 该示例使用$hour and $minute operators to return the corresponding portions of the date field:$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" }
}
}
}])
The operation returns the following result:该操作返回以下结果:
{
   "_id": 1,
   "nycHour" : 5,
   "nycMinute" : 24,
   "gmtHour" : 10,
   "gmtMinute" : 24,
   "nycOlsonHour" : 6,
   "nycOlsonMinute" : 24
}
Examples实例
Subtract A Fixed Amount减去固定金额
Consider a collection of system connection times like these:考虑一组系统连接时间,如下所示:
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")
}
]
)
Due to a service issue you need to subtract 3 hours from each of the January 2021 logout times. You can use 由于服务问题,您需要从2021年1月的每次注销时间中减去3小时。您可以在聚合管道中使用$dateSubtract in an aggregation pipeline to decrement the logoutTime.$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"
}
]
)
Two similar comparisons are made in the 在$match stage. $match阶段进行了两次类似的比较。First the 首先,$year and $month operators extract the year and month, respectively, from the logoutTime Date object. $year和$month运算符分别从logoutTimeDate对象中提取年份和月份。Then the month and year are checked to see if they match the selection targets. 然后检查月份和年份,看它们是否符合选择目标。Since "January" is encoded as "1", 由于“一月”被编码为“1”,当年和月等于($expr is true when the year and month are equal ($eq) to "2021" and "1".$eq)“2021”和“1”时,$expr为真。
The $project stage uses $dateSubtract to subtract 3 hours from the logoutTime of each selected dcoument.$project阶段使用$dateSubtract从每个选定数据文档的logoutTime中减去3小时。
Finaly, the 最后,$merge stage updates the collection, writing the new logoutTime for the modified documents.$merge阶段更新集合,为修改后的文档编写新的logoutTime。
Unlike 与$out, the $merge stage only updates the matched documents and preserves the rest of the collection. $out不同,$merge阶段只更新匹配的文档并保留集合的其余部分。For more details see: $out compared with $merge.有关更多详细信息,请参阅:$out与$merge的比较。
The resulting documents look like this:生成的文档如下所示:
{
 "_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")
}
Filter by Relative Dates按相对日期筛选
You want to send a survey to clients who have used your service in the past week. The 你想向过去一周使用过你服务的客户发送一份调查。$dateSubtract expression can create a range filter relative to the time the query is executed.$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"
}
}
}
}
]
)
The built in aggregation variable 内置聚合变量$$NOW returns the current datetime in ISODate format. $$NOW以ISODate格式返回当前日期时间。The $match stage uses the value in $$NOW to get today's date. $match阶段使用$$NOW中的值来获取今天的日期。Then the comparison expression (然后,比较表达式($expr) filters the collection using greater than ($gt) and $dateSubtract to match documents that have a logoutTime in the past week.$expr)使用大于($gt)和$dateSubtract筛选集合,以匹配在过去一周中具有logoutTime的文档。
The $project stage uses the $dateToString expression to convert the dates to a more readable format. $project阶段使用$dateToString表达式将日期转换为可读性更强的格式。Without the conversion MongoDB would return the date in ISODate format. 如果没有转换,MongoDB将以ISODate格式返回日期。The output shows two customers have logged out in the last week.输出显示上周有两个客户已注销。
{ "custId" : 459, "loggedOut" : "2021-02-17" }
{ "custId" : 460, "loggedOut" : "2021-02-18" }
Adjust for Daylight Savings Time夏令时调整
All dates are stored internally in UTC time. 所有日期都以UTC时间存储在内部。When a 如果指定了timezone is specified, $dateSubtract uses local time to carry out the calculations. The results are displayed in UTC.timezone,$dateSubtract将使用本地时间进行计算。结果以UTC显示。
You have customers in several timezones and you want to see what effect daylight savings time might have on your billing periods if you bill by 您有几个时区的客户,您想看看如果您按day or by hour.day或按hour计费,夏令时可能会对您的计费周期产生什么影响。
Create this collection of connection times:创建此连接时间集合:
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")
}
]
)
First subtract 1 day, then subtract 24 hours from the 首先从每个文档中的login dates in each document.login日期减去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()
The $dateToString expression reformats the output for readability. Results are summarized here:$dateToString表达式重新格式化输出以提高可读性。结果总结如下:
| New York | Mexico City | |
|---|---|---|
| Start | 2021-03-14 15:00 | 2021-03-14 15:00 | 
| Start, TZ Info | 2021-03-14 11:00 | 2021-03-14 04:00 | 
| 1 Day | 2021-03-13 16:00 | 2021-03-13 15:00 | 
| 1 Day, TZInfo | 2021-03-13 11:00 | 2021-03-13 09:00 | 
| 24 Hours | 2021-03-13 15:00 | 2021-03-13 15:00 | 
| 24 Hours, TZInfo | 2021-03-13 10:00 | 2021-03-13 09:00 | 
The chart highlights several points:该图表突出显示了以下几点:
Unformatted dates are returned in UTC.未格式化的日期以UTC返回。The纽约的$loginfor New York is UTC -5, however thestart,days, andhoursrows display the time in UTC.$login是UTC-5,但是start、days和hours行显示UTC时间。March 14th is the start of DST in New York, but not in Mexico.3月14日是纽约夏令时的开始,但墨西哥没有。The calculated time is adjusted when a location switches to DST and crosses from one当位置切换到夏令时并从一天穿越到下一天时,计算的时间会进行调整。dayto the next.DST modifies the length of the夏令时修改的是一天的长度,而不是小时的长度。day, not thehour.There is no DST change for夏令时在数小时内没有变化。hours.There is an only an adjustment for DST when the measurement当测量unitisdayor larger and the computation crosses a clock change in the specifiedtimezone.unit为day或更大,并且计算跨越指定timezone的时钟变化时,仅对DST进行调整。