我有一个包含如下数据的集合:
{
"_id": ObjectId("95159a08a27971c35a2683f"),
"Date": ISODate("2018-04-03T07:00:00Z"),
"Employee": "Bill",
"Hours": 7.5
}
{
"_id": ObjectId("372c6be4912fdd32398382f"),
"Date": ISODate("2018-04-05T07:00:00Z"),
"Employee": "Bill",
"Hours": 2
}
我想得到每周的总小时数,但本周需要从周六开始,到周五结束。如果我在标准周工作,我会这样做:
db.myCollection.aggregate(
{$match: {
Employee: "Bill",
Date: {
$gte: ISODate("2018-03-15T07:00:00Z"),
$lte: ISODate("2018-04-06T07:00:00Z")
}
}},
{$group: {
_id: {$week: "$Date"},
hours: {$sum: "$Hours"}
}
}
)
在星期日和星期六结束的标准周内工作正常。
我如何修改它以使用我描述的非标准周?在查询数据并在代码级别手动聚合时,我会更好吗?我可以按周累计Date - 1 day
还是太奇怪了?
更新
如果有人需要多年来完成这项工作,他们可以使用下面的Neil答案的更新版本:
{ "$group": {
"_id": {
"week":{
"$let": {
"vars": {
"satWeek": {
"$cond": {
"if": { "$eq": [ { "$dayOfWeek": "$Date" }, 7 ] },
"then": { "$add": [ { "$week": "$Date" }, 1 ] },
"else": { "$week": "$Date" }
}
}
},
"in": {
"$cond": {
"if": { "$gt": ["$$satWeek", 52] },
"then": 0,
"else": "$$satWeek"
}
}
}
},
"year": { "$year": "$Date" }
},
"hours": { "$sum": "$hours" }
}}
答案 0 :(得分:1)
好$week
根据“输入”日期返回,因此即使您将其调整为一天,Date - 1 day
仍将在“前一周”基于从该输入返回的内容
当然,最好让“服务器”执行此类操作,否则您只是“通过线路”提取大量数据,这首先避免了使用数据库的问题。 / p>
简而言之,“从星期六开始”只是意味着当{strong>星期六日时Week 1
成为Week 2
等等。所以week + 1
。唯一真正的警告是,Week 52
以上的任何内容都会成为Week 0
。
因此:
{ "$group": {
"_id": {
"$let": {
"vars": {
"satWeek": {
"$cond": {
"if": { "$eq": [ { "$dayOfWeek": "$Date" }, 7 ] },
"then": { "$add": [ { "$week": "$Date" }, 1 ] },
"else": { "$week": "$Date" }
}
}
},
"in": {
"$cond": {
"if": { "$gt": ["$$satWeek", 52] },
"then": 0,
"else": "$$satWeek"
}
}
}
},
"hours": { "$sum": "$hours" }
}}
主要调整点基于$dayOfWeek
的测试,其中星期六返回7
。
当然,它是52
还是53
作为边界取决于它是否是闰年,但是因为你想按“周”聚合,那么我认为你只需要一年最多“,然后根据您的日期选择是否在闰年内,可以将其调整为输入参数。
当然,调整编码更加体贴。但基本原则是调整“输出周”而不是“输入日期”
作为一个替代案例,我猜Date plus 1 day
实际上可以让你得到同样的结果,可以向前倾斜所有日期:
{ "$group": {
"_id": { "$week": { "$add": [ "$Date", 1000 * 60 * 60 * 24 ] } },
"hours": { "$sum": : "$hours" }
}}
如果你需要本地时区调整,那么从MongoDB 3.6你可以简单地包括时区信息来调整:
{ "$group": {
"_id": {
"$week": {
"date": { "$add": [ "$Date", 1000 * 60 * 60 * 24 ] },
"timezone": "America/Chicago"
}
},
"hours": { "$sum": : "$hours" }
}}
同样请注意,MongoDB 3.4中有$isoWeek
和类似的函数,您可以在其中进行一些不同的处理:
以ISO 8601格式返回周数,范围从1到53.周数从1开始,周(星期一到星期日)包含年份的第一个星期四。
因此,所有数学都将基于星期一而不是星期日,并考虑到一年中的哪一天被计为“第一周”,以及开始来自1
而不是0
。