2012-12-06 50 views
0

我有一個集合在具有這種結構的用戶文檔:

{ "_id" : ObjectId("4fb54ef46d93b33b21003951"), 
    "activities" : [ 
    { "id" : ObjectId("4fd66f9001e7fe9f03000065"), 
     "type" : "checkin", 
     "date_time_created" : Date(1339453328000)}, 
    { "date_time_created" : Date(1337351732000), 
     "date_time_updated" : Date(1337351952635), 
     "id" : ObjectId("4fb65e346d93b3fe77000000")} 
    ] 
} 

我可以輕鬆地查詢基於日期這些文件:

User.where( 
    :activities => { 
    '$elemMatch' => { 
     :date_time_created => { '$gte' => start_date, '$lt' => end_date } 
    } 
    } 
).length 

根據日誌:

MOPED:127.0。 0.1:27017 COMMAND database = db command = {:count =>「users」,:query => {「activities」=> {「$ elemMatch」=> {「date_time_created」=> {「$ gte」=> 05-10 00:00:00 UTC,「$ lt」=> 2012-07-12 00:00:00 UTC}}}}}(0.5260ms)

我得到了我需要的結果。

然而,當我試圖使用基於同一標準的新的聚合函數和$匹配:

User.collection.aggregate([ 
    { "$match" => { 
    :activities => { 
     '$elemMatch' => { 
     :date_time_created => { '$gte' => start_date, '$lt' => end_date } 
     } 
    } 
    } } 
]).length 

根據日誌:

MOPED:127.0.0.1:27017命令管理= db命令= {:aggregate =>「users」,:pipeline => [{「$ match」=> {:activities => {「$ elemMatch」=> {「date_time_created」=> {「$ gte」=> 「2012年5月10日星期四」,「$ lt」=> Thu,2012年7月12日}}}}}]}(0.6049ms)

「start_date」和「end_date」是Ruby Date對象, h查詢。但是,當我查看日誌時,它們會變成不同的格式。當我嘗試強制使用類似start_date.strftime(「%Y-%m-%d」)的格式時,它仍然不起作用。

集合管道中還有其他函數,但是我把它們取出來了,但仍然出現錯誤。

我如何獲得聚合函數在日期上匹配?

+0

你不需要$ elemMatch在這裏 - 你可以刪除它,看看這是否會改變發生了什麼? $ elemMatch用於比較數組元素的兩個不同屬性,這裏是測試單個值。 –

回答

6

下面的測試使用的聚合框架近似的邏輯等價您的查詢。

如果有多個匹配的數組元素,首先$展開數組,$ match,然後$ group使用$ addToSet。請注意,這是一個有損耗的過程,但如果您只需要計數或ID,則這是可以接受的。

希望這可以幫助。

測試/單位/ user_test.rb

require 'test_helper' 

class UserTest < ActiveSupport::TestCase 
    def setup 
    User.delete_all 
    end 

    test "user aggregate" do 
    User.create(
     activities: [ 
      { id: Moped::BSON::ObjectId("4fd66f9001e7fe9f03000065"), 
      type: "checkin", 
      date_time_created: Time.at(1339453328000) }, 
      { date_time_created: Time.at(1337351732000), 
      date_time_updated: Time.at(1337351952635), 
      id: Moped::BSON::ObjectId("4fb65e346d93b3fe77000000") } 
     ] 
    ) 
    start_date = Time.at(1339453328000) 
    end_date = start_date + 24*60*60 
    assert_equal(1, User.where(
     :activities => { 
      '$elemMatch' => { 
       :date_time_created => { '$gte' => start_date, '$lt' => end_date } 
      } 
     } 
    ).length) 
    assert_equal(1, User.collection.aggregate([ 
     { '$unwind' => '$activities' }, 
     { '$match' => { '$and' => [ 
      { 'activities.date_time_created' => { '$gte' => start_date } }, 
      { 'activities.date_time_created' => { '$lt' => end_date } } 
     ] } }, 
     { '$group' => { '_id' => '$_id', 'activities' => { '$addToSet' => '$activities' } } } 
    ]).length) 
    end 
end 
-2

對紅寶石沒有太大的影響,但如果你可以粘貼蒙戈殼,我可以幫忙。

有幾點建議:1。 您使用elemMatch所以你應該使用$放鬆後 2.您嘗試使用$匹配

0

糾正總喜歡這類型的比賽:

{:$match=>{ :created_at=>{:$gte=>2017-03-07 00:36:30 +0700}}} 

這意味着你應該使用方法:

match_na = { 
    '$match': {created_at: { '$gte': (Time.now-30.days) } } 
} 

請預告:不要使用Time.zone.now(因爲輸出將是另一種格式)。我很確定100%左右。這需要我3個小時。

還是那句話:讓日期或時間的格式是這樣的:

2017-03-07 00:36:30 +0700 

不是這個:

Mon, 03 Apr 2017 00:34:14 ICT +07:00 

或簡單的方法只是:使用方法mongoize

(Date.today - 30.days).mongoize