我有一个MongoDB集合,其中包含与日期相关的事件。像这样:
{
"year" : 1985,
"month" : 4,
"day" : 16,
"name" : "J"
},
{
"year" : 1985,
"month" : 9,
"day" : 16,
"name" : "E"
},
{
"year" : 1950,
"month" : 11,
"day" : 11,
"name" : "M"
},
{
"year" : 1947,
"month" : 5,
"day" : 6,
"name" : "D"
}
我想要一个从今天开始下一个生日的MongoDB查询。例如,如果今天是9月25日,我的收藏中的下一个生日将是11月11日,对应于name
等于"M"
的条目。
我会接受添加Date
类型的字段,移除我当前的year
,month
和day
字段,或其他任何内容,以便有效地实现我的目标目标
我正在使用MongoDB v3.4。
答案 0 :(得分:0)
好的,我可以告诉你基本上需要两个查询来完成这项工作。我不是Mongo专家,但是这将为您提供您现在所需要的/为您提供正确的研究方向。这两个查询如下:
db.YOUR_COLLECTION.find({ $where: "this.year = input_year & this.month > input_month & this.day > input_day" }).sort({ month: 1, day: 1 })
// Gets you back all the entries that have a month greater than the input month.
db.YOUR_COLLECTION.find({ $where: "this.year > input_year }).sort({ year: 1, month: 1, day: 1 })
// Gets you back all the entries that start at next year and go forward. This could probably be optimized a bit at some point.
请注意,在第一种情况下,我先按月份订购,然后按升序订购,按年份订购第二份作为额外参数。我也要归还所有的行。在实践中,您可能希望对某个结果进行限制。无论哪种方式,您都需要运行第一个查询来处理下一个日期未包装到下一年的情况。如果没有返回结果,那么您将需要第二个查询将在下一年开始并向前搜索。如果这不能完全回答你的问题,请告诉我。
答案 1 :(得分:0)
最后我在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
处于闰年,则在dayofYear
减去1到birthday
字段,并计算每个生日与今天之间的差异。pPast
中将365添加到过去的生日以获得positiveDiff
字段。pSort
按positiveDiff
字段降序排序,因此我们可以列出下一个生日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
字段的特定日期的下一个生日。
我愿意接受任何改变,特别是可读性和效率改进。