2017-09-25 54 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. 

注意的是,在第一種情況下,我第一次訂購他們的月,日升序和第二的訂單逐年作爲一個額外的參數。我也返回所有行。在實踐中,您可能想要對某個結果進行限制。無論哪種方式,您都需要運行第一個查詢來處理下一個日期未包含到下一年的情況。如果沒有返回結果,那麼您需要第二個將在下一年開始並向前搜索的查詢。如果這不能完全回答你的問題,請告訴我。