2014-09-03 47 views
0

我想要查詢文檔中的數組元素的一個/多個匹配字段(也可以包括子文檔)。查詢具有完全匹配字段的數組的元素Java中的MongoDB

例如:

我的收藏包括以下文件:

{ 
    "_id": 1, 
    "index": 1, 
    "elements":[ 
     { 
      "name":"test", 
      "date":"Mon Sep 01 01:00:00 EEST 2014" , 
      "tag":1 
     }, 
     { 
      "name": "test2", 
      "date": "Mon Sep 01 01:00:00 EEST 2014", 
      "tag": 2 
     }, 
     { 
      "name": "test", 
      "date": "Mon Sep 01 02:00:00 EEST 2014", 
      "tag": 3 
     } 
    ] 
}, 
{ 
    "_id":2, 
    "index":2, 
    "elements":[ 
     { 
      "name":"test", 
      "date":"Mon Sep 01 01:00:00 EEST 2014" , 
      "tag":1 
     }, 
     { 
      "name": "test2", 
      "date": "Mon Sep 01 01:00:00 EEST 2014", 
      "tag":2 
     }, 
     { 
      "name":"test", 
      "date":"Mon Sep 01 01:10:00 EEST 2014", 
      "tag":3 
     } 
    ] 
}, 
{ 
    "_id": 3, 
    "index": 3, 
    "elements": [ 
     { 
      "name": "test", 
      "date": "Mon Sep 01 01:00:00 EEST 2014", 
      "tag":1 
     }, 
     { 
      "name": "test2", 
      "date": "Mon Sep 01 01:00:00 EEST 2014", 
      "tag":2 
     }, 
     { 
      "name": "test", 
      "date": "Mon Sep 01 01:10:00 EEST 2014", 
      "tag":3 
     } 
    ] 
} 

我希望我的查詢結果返回我的文檔象下面這樣:

{ 
    "_id":1, 
    "index": 1, 
    "elements":[ 
     { 
      "name":"test", 
      "date":"Mon Sep 01 02:00:00 EEST 2014" , 
      "tag":3 
     } 
    ] 
} 

爲了提供這種我寫了一個查詢

Date dCriteria = new SimpleDateFormat("dd/MM/yy HH:mm:ss").parse("01/09/2014 05:00:00"); 

Query find = new Query(Criteria.where("index").is(3)); //To find matching documents 
find.fields().elemMatch(
    "elements", 
    Criteria.where("name").is("test").and("date").gte(dCriteria))); 

mongotemplate.findOne(find, Document.class); 

在MongoDB的shell命令這意味着爲:

db.collection.find(
    { "index": 3 }, 
    { "elements": { 
     "$elemMatch": { 
      "name": "test", 
      "date": { 
       "$gte": { "$date":"2014-09-01T02:00:000Z" } 
      } 
     } 
    } 
)   

但它返回以下結果:

{ 
    "_id": 0, 
    "index": 0, 
    "elements":[ 
     { 
      "name": "test", 
      "date": "Mon Sep 01 01:00:00 EEST 2014", 
      "tag":1 
     } 
    ] 
} 

這是確定省略_id和指數的Fileds但它返回的第一macting元素數組由於匹配條件,要麼匹配「名稱」:「測試」或「日期」大於等於dCriteria,但我想要的是在同一時間匹配兩個標準。

爲了這一點,我必須使用$ elemMatch運營商查詢exatcly多個字段在一個數組元素的同時匹配。但我不知道如何在我的投影中使用它的語法。

回答

1

MongoDB中保存日期,UTC,這也是一般的存儲日期,因爲它允許轉換和來自各時區沒有工作離開原點原始點一般最佳實踐。

因此,它是最肯定的是,這裏的實際日期確實是UTC,但是您傳遞從不同的時區構建的價值。驅動程序實際上序列化具有紀元時間戳的BSON請求並註明「日期」BSON類型。這意味着您的輸入現在被時區差異「傾斜」。在這種情況下,取消3個小時來表示UTC,因此轉換後的日期比您想象的早3個小時。

如果您有附帶在特定時區的日期源的數據,那麼你需要先轉換這一點,既作爲輸入,並在用戶界面演示,如果你打算顯示的本地時間值。

因此,無論轉換還是構建爲UTC:

// org.joda.time as Date constructor is deprecated 
    Date dCriteria = new DateTime(2014,9,1,1,10,DateTimeZone.UTC).toDate(); 

    Query find = new Query(Criteria.where("index").is(3)); //To find matching documents 
    find.fields().elemMatch(
      "elements", 
      Criteria.where("name").is("test").and("date").gte(dCriteria) 
    ); 

    System.out.println(find); 

你在哪裏不確定的結果查詢將如何構建,打印出來的一般調試。您應該在日誌級別執行此操作,您可以在生產中對其進行壓制。

如上所述,這形成是一樣的,你引用的外殼查詢,但因爲它代表你的代碼是不是因爲它使用的是本地時間,而不是UTC。

你也幾乎總是真的想在查詢中做你的元素匹配而不是在投影中。一旦您將您的$elemMatch移動到您的語句的查詢部分,即可使用positional $運算符來計算獲得的「第一個」匹配。這可以確保當數組中沒有任何元素實際符合條件時,不會獲得空數組。

+0

嗨尼爾,其實我的問題是不符合日期。我也知道mongo使用UTC格式,不關心日期。我的問題是查詢結果。我可以將$ elemMatch條件放入搜索查詢中,以免在投影之前得到空白文檔,這很重要。但是問題來自於獲取數組元素中唯一匹配的數組元素。這意味着我應該使用(不確定)$ elemMatch與另一個elemMatch操作符來獲取我的查詢的匹配元素,這是字段名稱和測試。 – 2014-09-05 06:51:01

+0

@ C.Kaya您的問題與日期。你得到錯誤元素的原因是因爲TimeZone差異的調整時間。您應該能夠基本上完成我在定義查詢結束時所做的工作。記錄輸出以查看序列化表單。您的代碼不會與您發佈到shell的查詢產生相同的結果。我在做什麼。 – 2014-09-05 07:01:08

+0

我編輯我的時間格式,實際上我在我的帖子中使用。下面是我用過的匹配元素的查詢:Query:{「index」:1,「alarms」:{「$ elemMatch」:{「name」:「Test1」,「date」:{「$ gte」: {「$ date」:「2014-09-01T02:00:00.000Z」}}}}},Fields:{「alarms」:{「$ elemMatch」:{「name」:「Test1」,「date」: {「$ gte」:{「$ date」:「2014-09-01T02:00:00.000Z」}}}}},排序:null – 2014-09-05 07:20:19