【问题标题】:Get Number of weekdays between two dates in Mongo DB获取Mongodb中两个日期之间的工作日数
【发布时间】:2016-08-31 13:47:58
【问题描述】:

我是 Mongo DB 的新手。谁能帮助我获取两个给定日期之间的工作日数。

$dayOfWeek 将给出日期的值 0 代表星期日,7 代表星期六。

但我的问题是如何增加从开始日期到结束日期的日期以找到工作日数。

样本数据:

 > db.data.insert({"startDate":ISODate('2016-0101'), "endDate":ISODate('2016-02-02')})  

    WriteResult({ "nInserted" : 1 })
    > db.data.find().pretty()
    { 
            "_id" : ObjectId("57c6e6a6a1e49d654caca17a"), 
            "startDate" : ISODate("2016-01-01T00:00:00Z"),
            "endDate" : ISODate("2016-02-02T00:00:00Z")
    }

现在需要找出开始日期 (2016-01-01) 和结束日期 (2016-02-02) 之间的工作日数。

我可以编写一个接受开始日期和结束日期的函数,但是在该函数中如何从开始日期迭代到结束日期?

请求任何帮助。

【问题讨论】:

  • 您能在需要的地方添加查询吗?
  • @tarashypka :更新了我的问题
  • MongoDB 接受简单的 Javascript,因此任何现有的解决方案都应该可以工作:例如参见 stackoverflow.com/questions/3464268/…
  • 开始日期是工作日和/或结束日期是工作日的情况怎么办?您想要两个日期(包括这些日期)之间的工作日数量吗?
  • @tarashypka 是的,如果是工作日,我需要计算包括选择的日期。

标签: mongodb date mongodb-query


【解决方案1】:

要查找 2 个日期之间的工作日总数,您可以从总天数中减去周末总数。这里的主要问题是找到周末的总数。

示例 [2016-12-23; 2017-01-01]

_Dec23___Dec24___Dec25____... ____Dec30___Dec31___Jan01___...

__Fri______Sat_____Sun______...______Fri_____Sat_____Sun_____...

如您所见,这些日期之间有 4 个周末(Dec24、Dec25、Dec31 和 Jan01)。

解决方案

以编程方式解决它的一种方法是使用 聚合框架 及其 算术日期聚合运算符

可以通过将任务拆分为 2 个子任务来完成:

  1. startDateendDate(将其命名为weeksBetween)之间找出整周的数量。在上面的例子中weeksBetween = 1
  2. startDate + 7 * weeksBetweenendDate(命名为left,可能是1、2、3、4、5 或6)之间找到全天 的数量。在上面的例子中left = 3(剩下的日子是周五、周六和周日)。感兴趣的是剩下几天的周末数量(将其命名为left_weekends,可能是 0,1 或 2)。在上面的例子中left_weekends = 2

那么,周末的总数是2 * weeksBetween + left_weekends。在上面的例子中是2 * 1 + 2 = 4

要查找left_weekends,您可以使用$dayOfWeek 日期聚合运算符

  1. 如果left 是 1,2,3,4,5 或 left_weekends = 2 如果 left 是 6(包括太阳和下一个星期六),则为太阳 dayOfWeek = 1left_weekends = 1
  2. 对于周一dayOfWeek = 2left_weekends = 0 如果left 是1,2,3,4 或left_weekends = 1 如果left 是5 或left_weekends = 2 如果left 是6(包括下一个周六和周日)。

...

  1. 代表星期六 dayOfWeek = 7left_weekends = 2 代表任何 left

因此,我们可以使用以下规则:

  1. 如果remainder > 7,那么left_weekends = 2

  2. 如果remainder = 7,则left_weekends = 1 表示周一至周六,left_weekends = 2 表示周日。

  3. 如果 remainder < 7left_weekends = 0 表示周一至周六,left_weekends = 1 表示周日。

这里,remainder = dayOfWeek + left

查询

db.dates.aggregate(
  {
    $project:
      {
        "daysBetween":
          {
            $add: [
              {
                $floor:
                  {
                    $divide: [
                      { $subtract: [ "$endDate", "$startDate" ] },
                      1000 * 60 * 60 * 24
                    ]
                  }
              },
              1
            ]
          },
        "startDay": { $dayOfWeek: "$startDate" },
        "endDay": { $dayOfWeek: "$endDate" }
      }
  },
  {
    $project:
      {
        "daysBetween": "$daysBetween",
        "weeksBetween": { $floor: { $divide: [ "$daysBetween", 7 ] } },
        "startDay": "$startDay",
        "remainder":
          {
            $add: [
              { $abs: { $subtract: [ "$endDay", "$startDay" ] } },
              "$startDay"
            ]
          }
      }
  },
  {
    $project:
      {
        "weekendsBetween":
          {
            $add: [
              { $multiply: [ "$weeksBetween", 2 ] },
              {
                $cond:
                  {
                    if: { $gt: [ "$remainder", 7 ] },
                    then: 2,
                    else:
                      {
                        $cond:
                          {
                            if: { $eq: [ "$remainder", 7 ] },
                            then: 1,
                            else: 0
                          }
                      }
                  }
              },
              { $cond: { if: { $eq: [ "$startDay", 1 ] }, then: 1, else: 0 } }
            ]
          },
        "daysBetween": "$daysBetween"
      }
  },
  {
    $project:
      {
        "weekdaysBetween": { $subtract: [ "$daysBetween", "$weekendsBetween" ] }
      }
  }
);

示例

{ "_id": 1, "startDate": ISODate("2016-12-23T00:00:00Z"), 
            "endDate":   ISODate("2017-01-01T00:00:00Z") }
{ "_id": 2, "startDate": ISODate("2016-12-23T00:00:00Z"), 
            "endDate":   ISODate("2017-01-09T00:00:00Z") }
{ "_id": 3, "startDate": ISODate("2016-12-23T00:00:00Z"), 
            "endDate":   ISODate("2017-01-18T00:00:00Z") }  

结果

{ "_id": 1, "weekdaysBetween" : 6 }
{ "_id": 2, "weekdaysBetween" : 12 }
{ "_id": 3, "weekdaysBetween" : 19 }

PS 延长最后一个$project 阶段,您还可以获得两个日期之间的总天数和周末数。在测试查询之前不要忘记更改集合名称。

【讨论】:

  • 当我执行给定的代码时,我收到以下错误......关于这个的想法???错误:断言:命令失败:{“errmsg”:“异常:无效的运算符'$sum'”,“代码”:15999,“ok”:0 }:聚合失败:聚合在 doassert 处出现错误()失败(src/mongo/shell/assert.js:11:14) 在 Function.assert.commandWorked (src/mongo/shell/assert.js:254:5) 在 DBCollection.aggregate (src/mongo/shell/collection.js :1278:12) at (shell):1:9 at src/mongo/shell/assert.js:13
  • 如果您的 MongoDB 版本早于 3.2,则使用 $add 算术聚合运算符 而不是 $sum。更新了答案。
  • 我厌倦了在tutorialspoint提供的编码场做这个
  • 它使用 v3.0.9。您可以使用db.version() 命令检查它。 $sum 运算符不适用于 v.3.0.9 的 $project 阶段。正如我在答案中所说和所做的那样,将其替换为 $add 运算符。
  • 我已将 sum 替换为 add 并删除了 $floor 和 $abs,因为它们也仅在 3.2 中可用。然后我得到像 { "_id" : ObjectId("57d011e6e6d6fa2c2c0998ae"), "weekdaysbetween" : null } 这样的输出,即使我将开始日期作为月份开始,结束日期作为月份结束日期。对此有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-12
  • 2014-03-05
  • 1970-01-01
相关资源
最近更新 更多