那麼你可能只是簡單地使用現有的date aggregation operator S作爲反對使用數學對「天」的轉換,你目前有:
db.getCollection('user').aggregate([
{ "$unwind": "$education" },
{ "$group": {
"_id": "$_id",
"years": {
"$sum": {
"$subtract": [
{ "$subtract": [
{ "$year": { "$ifNull": [ "$education.to", new Date() ] } },
{ "$year": "$education.from" }
]},
{ "$cond": {
"if": {
"$gt": [
{ "$month": { "$ifNull": [ "$education.to", new Date() ] } },
{ "$month": "$education.from" }
]
},
"then": 0,
"else": 1
}}
]
}
},
"months": {
"$sum": {
"$add": [
{ "$subtract": [
{ "$month": { "$ifNull": [ "$education.to", new Date() ] } },
{ "$month": "$education.from" }
]},
{ "$cond": {
"if": {
"$gt": [
{ "$month": { "$ifNull": ["$education.to", new Date() ] } },
{ "$month": "$education.from" }
]
},
"then": 0,
"else": 12
}}
]
}
},
"days": {
"$sum": {
"$add": [
{ "$subtract": [
{ "$dayOfYear": { "$ifNull": [ "$education.to", new Date() ] } },
{ "$dayOfYear": "$education.from" }
]},
{ "$cond": {
"if": {
"$gt": [
{ "$month": { "$ifNull": [ "$education.to", new Date() ] } },
{ "$month": "$education.from" }
]
},
"then": 0,
"else": 365
}}
]
}
}
}},
{ "$project": {
"years": {
"$add": [
"$years",
{ "$add": [
{ "$floor": { "$divide": [ "$months", 12 ] } },
{ "$floor": { "$divide": [ "$days", 365 ] } }
]}
]
},
"months": {
"$mod": [
{ "$add": [
"$months",
{ "$floor": {
"$multiply": [
{ "$divide": [ "$days", 365 ] },
12
]
}}
]},
12
]
},
"days": { "$mod": [ "$days", 365 ] }
}}
])
這是「之類的」近似的「天」和「幾個月」沒有必要的操作是閏年的「確定」,但是它會讓你獲得應該「足夠」的結果,用於大多數目的。
你甚至可以做到這一點沒有$unwind
只要你的MongoDB的版本是3.2或更高:
db.getCollection('user').aggregate([
{ "$addFields": {
"duration": {
"$let": {
"vars": {
"edu": {
"$map": {
"input": "$education",
"as": "e",
"in": {
"$let": {
"vars": { "toDate": { "$ifNull": ["$$e.to", new Date()] } },
"in": {
"years": {
"$subtract": [
{ "$subtract": [
{ "$year": "$$toDate" },
{ "$year": "$$e.from" }
]},
{ "$cond": {
"if": { "$gt": [{ "$month": "$$toDate" },{ "$month": "$$e.from" }] },
"then": 0,
"else": 1
}}
]
},
"months": {
"$add": [
{ "$subtract": [
{ "$ifNull": [{ "$month": "$$toDate" }, new Date() ] },
{ "$month": "$$e.from" }
]},
{ "$cond": {
"if": { "$gt": [{ "$month": "$$toDate" },{ "$month": "$$e.from" }] },
"then": 0,
"else": 12
}}
]
},
"days": {
"$add": [
{ "$subtract": [
{ "$ifNull": [{ "$dayOfYear": "$$toDate" }, new Date() ] },
{ "$dayOfYear": "$$e.from" }
]},
{ "$cond": {
"if": { "$gt": [{ "$month": "$$toDate" },{ "$month": "$$e.from" }] },
"then": 0,
"else": 365
}}
]
}
}
}
}
}
}
},
"in": {
"$let": {
"vars": {
"years": { "$sum": "$$edu.years" },
"months": { "$sum": "$$edu.months" },
"days": { "$sum": "$$edu.days" }
},
"in": {
"years": {
"$add": [
"$$years",
{ "$add": [
{ "$floor": { "$divide": [ "$$months", 12 ] } },
{ "$floor": { "$divide": [ "$$days", 365 ] } }
]}
]
},
"months": {
"$mod": [
{ "$add": [
"$$months",
{ "$floor": {
"$multiply": [
{ "$divide": [ "$$days", 365 ] },
12
]
}}
]},
12
]
},
"days": { "$mod": [ "$$days", 365 ] }
}
}
}
}
}
}}
])
這是因爲MongoDB的3.4你可以用數組或表達式的任意列表直接使用$sum
諸如$addFields
或$project
之類的階段,並且$map
可以針對每個陣列元素應用那些相同的「日期聚集運算符」表達式來代替首先執行$unwind
。
所以主要數學可以真正在「減少」數組的一部分中完成,然後每個總數可以由多年來的一般「因數」和任何來自任何數據的「模數」或「餘數」在數月和數天內超支。
本質返回:
{
"_id" : ObjectId("5a07688e98e4471d8aa87940"),
"education" : [
{
"courseName" : "Java",
"from" : ISODate("2010-12-08T00:00:00.000Z"),
"to" : ISODate("2011-05-31T00:00:00.000Z"),
"isGoingOn" : false
},
{
"courseName" : "PHP",
"from" : ISODate("2013-12-08T00:00:00.000Z"),
"to" : ISODate("2015-05-31T00:00:00.000Z"),
"isGoingOn" : false
},
{
"courseName" : "Mysql",
"from" : ISODate("2017-02-08T00:00:00.000Z"),
"to" : null,
"isGoingOn" : true
}
],
"duration" : {
"years" : 3.0,
"months" : 3.0,
"days" : 259.0
}
}
鑑於2017年11月11日
您的查詢'計算的年,月,day'分開,我想要的是像'1年2個月和10個一天,不像'1年,14個月,396天' – jones
@jones這不會發生。您可以使用生成的值形成一個「字符串」,但這只是將值連接成一個完整的字符串,這在客戶端代碼中更有意義。你真的應該讓數據庫自然地「減少」內容。正如這裏所示。並注意我實際上做了什麼,因爲我**實際上相應地調整了所有年份,月份和日期。 –
@jones認爲我誤解了你的評論。再看看,我的確在調整每個部分。這只是因爲這裏的數學與你所設想的不同。我從未達到14個月。這是積極的或消極的,然後相應調整。與年份相同,基於月份。 –