我有包含日期字段的集合。我按周和其他相关字段对记录进行分组。
这是我的聚合查询:
db.raw.aggregate([
{ "$match" : {
"Timestamp":{
"$gte": new Date("2012-05-30"),
"$lt": new Date("2014-07-31")
}
}},
{ "$group" : {
"_id":{
"ApplicationId": "$ApplicationId",
"Country": "$Country",
"week":{ "$week": "$Timestamp" }
},
"Date":{ "$first": "$Timestamp" },
"Visits": { "$sum": 1 }
}}
])
我想项目:从周数开始的访问和开始日期。
答案 0 :(得分:3)
您似乎想要一个"日期值"表示一周开始的日期。你最好的方法是"日期数学"在汇总运营商$dayOfWeek
的帮助下:
db.raw.aggregate([
{ "$match" : {
"Timestamp":{
"$gte": new Date("2012-05-30"),
"$lt": new Date("2014-07-31")
}
}},
{ "$group" : {
"_id":{
"ApplicationId": "$ApplicationId",
"Country": "$Country",
"weekStart":{
"$subtract": [
{ "$subtract": [
{ "$subtract": [ "$Timestamp", new Date("1970-01-01") ] },
{ "$cond": [
{ "$eq": [{ "$dayOfWeek": "$Timestamp" }, 1 ] },
0,
{ "$multiply": [
1000 * 60 * 60 * 24,
{ "$subtract": [{ "$dayOfWeek": "$Timestamp" }, 1 ] }
]}
]}
]},
{ "$mod": [
{ "$subtract": [
{ "$subtract": [ "$Timestamp", new Date("1970-01-01") ] },
{ "$cond": [
{ "$eq": [{ "$dayOfWeek": "$Timestamp" }, 1 ] },
0,
{ "$multiply": [
1000 * 60 * 60 * 24,
{ "$subtract": [{ "$dayOfWeek": "$Timestamp" }, 1 ] }
]}
]}
]},
1000 * 60 * 60 * 24
]}
]
}
},
"Date":{ "$first": "$Timestamp" },
"Visits": { "$sum": 1 }
}}
])
或者来自MongoDB 2.6及以上版本的$let
更清洁一点:
db.raw.aggregate([
{ "$match" : {
"Timestamp":{
"$gte": new Date("2012-05-30"),
"$lt": new Date("2014-07-31")
}
}},
{ "$group" : {
"_id":{
"ApplicationId": "$ApplicationId",
"Country": "$Country",
"weekStart":{
"$let": {
"vars": {
"dayMillis": 1000 * 60 * 60 * 24,
"beginWeek": {
"$subtract": [
{ "$subtract": [ "$Timestamp", new Date("1970-01-01") ] },
{ "$cond": [
{ "$eq": [{ "$dayOfWeek": "$Timestamp" }, 1 ] },
0,
{ "$multiply": [
1000 * 60 * 60 * 24,
{ "$subtract": [{ "$dayOfWeek": "$Timestamp" }, 1 ] }
]}
]}
]
}
},
"in": {
"$subtract": [
"$$beginWeek",
{ "$mod": [ "$$beginWeek", "$$dayMillis" ]}
]
}
}
}
},
"Date":{ "$first": "$Timestamp" },
"Visits": { "$sum": 1 }
}}
])
"分组"中的结果值是一个纪元毫秒,表示一周开始的一天的开始。 "本周的开始"通常被认为是"星期日",所以如果你想要另一天,那么你需要调整适当的金额。具有$dayMillis
变量值的$add
运算符可用于此处应用"星期一"例如。
它不是日期对象,但您可以轻松地将其提供给另一种方法,以便在后期处理中构建日期对象。
另请注意,您正在使用的其他内容(例如$first
)通常要求文档按特定顺序排序,或者通常由您的"时间戳"值。如果这些文档尚未订购,那么您首先$sort
或使用$min
之类的运算符来获取该范围内的第一个实际时间戳。
答案 1 :(得分:1)
对于mongo> = v3.4,请查看weekStart。 我们的想法是从给定的时间戳
中减去毫秒数db.raw.aggregate([
// stage 1
{ "$match" : {
"Timestamp":{
"$gte": ISODate("2012-05-30"),
"$lt": ISODate("2014-07-31")
}
}},
// stage 2
{ "$project" : {
ApplicationId: 1,
Country: 1,
week: {$isoWeek: "$Timestamp"},
// [TRICK IS HERE] Timestamp - dayOfWeek * msInOneDay
weekStart: { $dateToString: { format: "%Y-%m-%d", date: { // convert date
$subtract: ["$Timestamp", {$multiply: [ {$subtract:[{$isoDayOfWeek: "$Timestamp"},1]}, 86400000]}]
}}},
// stage 3
{ "$group" : {
"_id":{
"ApplicationId": "$ApplicationId",
"Country": "$Country",
"week": "$week"
},
"Date":{ "$first": "$weekStart" },
"Visits": { "$sum": 1 }
}}
])
答案 2 :(得分:1)
使用MongoDB 3.6
{
'$project' : {
'firstDateOfWeek': {
'$dateFromString': {
'dateString': {
'$concat': [
{
'$toString': '$_id.year'
},
'-',
{
'$toString': '$_id.week'
}
]
},
'format': "%G-%V"
}
}
}
}
答案 3 :(得分:0)
来自 mongo 3.6 https://docs.mongodb.com/manual/reference/operator/aggregation/dateFromParts/
db.raw.aggregate([
{
"$match": {
"Timestamp": {
"$gte": new Date("2012-05-30"),
"$lt": new Date("2014-07-31")
}
}
},
{
"$group": {
"_id": {
"ApplicationId": "$ApplicationId",
"Country": "$Country",
"week": {
"$isoWeek": "$Timestamp"
},
"year": {
"$year": "$Timestamp"
}
},
"Visits": {
"$sum": 1
}
}
},
{
"$addFields": {
"Date": {
$dateFromParts: {
isoWeekYear: '$_id.year',
isoWeek: '$_id.week',
isoDayOfWeek: 1
}
}
}
}
])