MongoDB聚合运算符:$dateDiff

文章目录

$dateDiff聚合运算符返回两个日期只差。

语法

js 复制代码
{
   $dateDiff: {
      startDate: <Expression>,
      endDate: <Expression>,
      unit: <Expression>,
      timezone: <tzExpression>,
      startOfWeek: <String>
   }
}

结束日期endDate减去开始日期startDate,返回指定时间单位unit的整数。

参数字段说明:

|字段|是否必须|描述|

|-|-|

|startDate|是|开始时间,可以是任何合法的日期、时间戳或ObjectID表达式|

|startDate|是|结束时间,可以是任何合法的日期、时间戳或ObjectID表达式|

|unit|是|时间单位,可以是结果为yearquarterweekmonthdayhourminutesecondmillisecond的表达式|

|timezone|否|执行操作的时区,<tzExpression>必须是能被解析为奥尔森时区标识符格式的字符串或UTC偏移量,如果timezone不指定,返回值显示为UTC|

|startOfWeek|否|当单位unitweek时使用,默认为星期日,可以是结果为monday (or mon)tuesday (or tue)wednesday (or wed)thursday (or thu)friday (or fri)saturday (or sat)sunday (or sun)之一的字符串表达式|

使用

没有小数单位

$dateDiff表达式返回以指定单位计算的开始日期和结束日期之间的整数差,持续时间是通过计算通过单位边界的次数来确定的,例如,相差 18 个月的两个日期将返回1年的差值,而不是1.5年。

周的开始

除非通过参数startOfWeek指定,否则一周的开始日期为周日。在指定日期的开始日期和结束日期之间开始的任何一周都会被计算在内。周计数不受日历月或日历年的限制。

时区

<timezone>字段中使用 Olson 时区标识符时,MongoDB 会应用 DST 偏移(如果适用于指定的时区)。

例如,包含以下文件的sales集合:

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

下面的聚合说明了 MongoDB 如何处理 Olson 时区标识符的 DST 偏移量。示例使用$hour$minute操作符返回日期字段的相应部分:

js 复制代码
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" }
       }
   }
}])

操作返回以下结果:

json 复制代码
{
   "_id": 1,
   "nycHour" : 5,
   "nycMinute" : 24,
   "gmtHour" : 10,
   "gmtMinute" : 24,
   "nycOlsonHour" : 6,
   "nycOlsonMinute" : 24
}

其它细节

该算法使用公历计算日期差异。闰年和夏令时计算在内,但不包括闰秒。返回的差值可以是负数。

举例

持续时间

创建一个消费订单集合:

js 复制代码
db.orders.insertMany(
   [
      {
         custId: 456,
         purchased: ISODate("2020-12-31"),
         delivered: ISODate("2021-01-05")
      },
      {
         custId: 457,
         purchased: ISODate("2021-02-28"),
         delivered: ISODate("2021-03-07")
      },
      {
         custId: 458,
         purchased: ISODate("2021-02-16"),
         delivered: ISODate("2021-02-18")
      }
   ]
)

在下面的例子中:

  • 返回平均交货天数
  • 使用dateDiff计算购买日期和交货日期之间的天数
js 复制代码
 db.orders.aggregate(
    [
       {
          $group:
             {
                 _id: null,
                 averageTime:
                    {
                       $avg:
                          {
                             $dateDiff:
                                {
                                    startDate: "$purchased",
                                    endDate: "$delivered",
                                    unit: "day"
                                }
                           }
                    }
             }
       },
       {
          $project:
             {
                _id: 0,
                numDays:
                   {
                      $trunc:
                         [ "$averageTime", 1 ]
                   }
             }
        }
    ]
)

$group阶段中的$avg累加器使用每个文档上的$dateDiff来获取购买日期和交付日期之间的时间。得出的值将作为averageTime返回。

平均时间的小数部分会在$project阶段被截断 ($trunc),从而产生类似这样的输出结果:

json 复制代码
{ "numDays" : 4.6 }

结果精度

创建subscriptions集合,其中包含订阅的开始日期和结束日期:

js 复制代码
db.subscriptions.insertMany(
   [
      {
         custId: 456,
         start: ISODate("2010-01-01"),
         end: ISODate("2011-01-01")
      },
      {
         custId: 457,
         start: ISODate("2010-01-01"),
         end: ISODate("2011-06-31")
      },
      {
         custId: 458,
         start: ISODate("2010-03-01"),
         end: ISODate("2010-04-30")
      }
   ]
)

$dateDiff表达式返回以整数单位表示的时间差,单位中没有小数部分。例如,以年为单位计算时,就没有半年。

在本例中,请注意单位的改变对返回精度的影响:

js 复制代码
db.subscriptions.aggregate(
   [
      {
         $project:
            {
               Start: "$start",
               End: "$end",
               years:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "year"
                        }
                  },
               months:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "month"
                        }
                  },
               days:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "day"
                        }
                  },
               _id: 0
            }
       }
   ]
 )

结果汇总如下表所示:

Start End Years Months Days
2010-01-01 2011-01-01 1 12 365
2010-01-01 2011-07-01 1 18 546
2010-03-01 2010-04-30 0 1 60

计数只在新单位开始时递增,因此第二行中的18个月为1年,第三行中的60天为1个月。

每月周数

创建一个months集合:

js 复制代码
db.months.insertMany(
     [
        {
           month: "January",
           start: ISODate("2021-01-01"),
           end: ISODate("2021-01-31")
        },
        {
           month: "February",
           start: ISODate("2021-02-01"),
           end: ISODate("2021-02-28")
        },
        {
           month: "March",
           start: ISODate("2021-03-01"),
           end: ISODate("2021-03-31")
        },
     ]
   )

可以使用以下代码更改每周的开始时间,并计算出每月的周数:

js 复制代码
db.months.aggregate(
   [
      {
         $project:
            {
               wks_default:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "week"
                        }
                  },
               wks_monday:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "week",
                           startOfWeek: "Monday"
                        }
                  },
               wks_friday:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "week",
                           startOfWeek: "fri"
                        }
                  },
               _id: 0
            }
       }
   ]
 )

下表对结果进行了汇总:

Month Sunday Monday Friday
January 5 4 4
February 4 3 4
March 4 4 4

从结果来看:

  • 当 "周初 "是周日时,2021年1月的第5周从31日开始。
  • 由于31日是周日,且位于开始日期和结束日期之间,因此计数会增加一周。
  • 即使日历周在结束日期之后或在下一个日历期间结束,周计数也会递增。
相关推荐
bkspiderx5 分钟前
libmysqlclient:MySQL 底层客户端库的全面指南
数据库·mysql·mysqlclient·libmysqlclient·mysql 底层客户端库
Arva .5 分钟前
详细描述一条 SQL 在 MySQL 中的执行过程
数据库·sql·mysql
数据库学啊9 分钟前
好用的车联网时序数据库机构有哪些
大数据·数据库·时序数据库
Elastic 中国社区官方博客25 分钟前
如何通过个性化、分群感知排序来提升电商搜索相关性
大数据·数据库·elasticsearch·搜索引擎·全文检索
urkay-30 分钟前
Android 数据库操作线程安全吗
android·数据库·安全
ZeroNews内网穿透33 分钟前
RStudio Server 结合 ZeroNews,实现远程访问管理
运维·服务器·网络·数据库·网络协议·安全·web安全
李白你好37 分钟前
Redis 漏洞图形化利用工具
数据库·redis·缓存
JosieBook43 分钟前
【数据库】IoTDB数据库与时序大模型深度融合,开启数据智能分析新范式
数据库·iotdb
Logic1011 小时前
《Mysql数据库应用》 第2版 郭文明 实验4 视图和索引的构建与使用核心操作与思路解析
数据库·sql·mysql·学习笔记·计算机网络技术·形考作业·国家开放大学
码农12138号1 小时前
网络安全-SQL注入
数据库·web安全·sql注入