2017-09-25 67 views
-2

我有一个MongoDB集合,其中包含与日期一致的事件。事情是这样的:在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类型的字段,删除我目前yearmonthday领域,或任何以有效率的方式来实现我的目标。

我正在使用MongoDB v3.4。

+0

我假设你想包好吗?因此,如果您今天是12月12日,那么您会希望以名称“J”返回条目,因为这是下个月? –

+0

@MichaelPlatt是的。 – logoff

回答

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" 
} 

然后,我建立了几个结构,聚集管道使用方法:

  1. pDayOfYear得到的生日,今天的年连续一年,使用$dayOfYear operator
  2. pLeapYear如果birthday处于闰年并且计算每个生日和今天之间的差异,则将012减去1到dayofYear字段。
  3. pPast添加365到过去的生日有positiveDiff字段。
  4. 在递减顺序由positiveDiffpSort排序结果,所以我们可以可以有下一个生日
  5. 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字段。

我接受任何改变,特别是可读性和效率的改进。

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. 

注意的是,在第一种情况下,我第一次订购他们的月,日升序和第二的订单逐年作为一个额外的参数。我也返回所有行。在实践中,您可能想要对某个结果进行限制。无论哪种方式,您都需要运行第一个查询来处理下一个日期未包含到下一年的情况。如果没有返回结果,那么您需要第二个将在下一年开始并向前搜索的查询。如果这不能完全回答你的问题,请告诉我。