最后我在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