最後我在this answer後得到了答案。它使用the Aggregation Pipeline。
首先,我決定使用Date
/ISODate
類型來存儲生日,而不是個人年/月/日字段。所以我test
集將有這些項:
{
"birthday" : ISODate("1985-04-16T10:00:00.000Z"),
"name" : "J"
}
{
"birthday" : ISODate("1985-09-16T11:00:00.000Z"),
"name" : "E"
}
{
"birthday" : ISODate("1950-11-11T11:00:00.000Z"),
"name" : "M"
}
{
"birthday" : ISODate("1947-05-06T10:00:00.000Z"),
"name" : "D"
}
然後,我建立了幾個結構,聚集管道使用方法:
- 在
pDayOfYear
得到的生日,今天的年連續一年,使用$dayOfYear operator。
pLeapYear
如果birthday
處於閏年並且計算每個生日和今天之間的差異,則將012減去1到dayofYear
字段。
- 在
pPast
添加365到過去的生日有positiveDiff
字段。
- 在遞減順序由
positiveDiff
場pSort
排序結果,所以我們可以可以有下一個生日
- 在
pFirst
只得到第一個結果列表。
查詢看起來像:
pDayOfYear = {
"$project": {
"birthday": 1,
"todayDayOfYear": {"$dayOfYear": new ISODate()},
"leap": {"$or": [
{"$eq": [0, {"$mod": [{"$year": "$birthday"}, 400]}]},
{"$and": [
{"$eq": [0, {"$mod": [{"$year": "$birthday"}, 4]}]},
{"$ne": [0, {"$mod": [{"$year": "$birthday"}, 100]}]}
]}
]},
"dayOfYear": {"$dayOfYear": "$birthday"}
}
}
pLeapYear = {
"$project": {
"birthday": 1,
"todayDayOfYear": 1,
"dayOfYear": {
"$subtract": [
"$dayOfYear",
{
"$cond": [
{"$and":
["$leap",
{"$gt": ["$dayOfYear", 59]}
]},
1,
0]
}
]},
"diff": { "$subtract": [ "$dayOfYear", "$todayDayOfYear"] }
}
}
pPast = {
"$project": {
"diff": 1,
"birthday": 1,
"positiveDiff": {
"$cond": {
"if": { "$lt": ["$diff", 0 ]},
"then": { "$add": ["$diff", 365] },
"else": "$diff"
},
}
}
}
pSort = {
"$sort": {
"positiveDiff": 1
}
}
pFirst = {
"$group": {
"_id": "first_birthday",
"first": {
"$first": "$$ROOT"
}
}
}
db.getCollection('tests').aggregate(pDayOfYear, pLeapYear, pPast, pSort, pFirst);
所以我會得到下一個生日ID,我可以通過ID查詢的字段。可以在任何日期的某個特定日期的下一個生日將更改todayDayOfYear
字段。
我接受任何改變,特別是可讀性和效率的改進。
我假設你想包好嗎?因此,如果您今天是12月12日,那麼您會希望以名稱「J」返回條目,因爲這是下個月? –
@MichaelPlatt是的。 – logoff