2016-09-24 36 views
1

我是MongoDB的新手,並且在爲我正在開發的新項目設置特定查詢時遇到了一些困難。如何在MongoDB中找到深嵌入數組的對象?

我有一個數據結構,看起來像這樣(簡體版):

games: {_id: ..., scenes: [{_id: ..., views: [{_id: ...}]}]} 

(即遊戲中包含的場景集合,場景中包含的視圖的集合)。

我想在這裏查詢的是一個特定的視圖對象。我想答案包括使用$ elemMatch,但我該如何設置?一些研究+玩耍後,我知道我能做到這一點得到了現場:

db.collection("games").findOne({ 
    _id: ObjectId(req.params.gid)}, 
    { 
    scenes: { 
     $elemMatch: {_id: ObjectId(req.params.sid)} 
    } 
}... 

但我怎麼延長這個,使其只拉特定視圖我感興趣的(由_id) ?

我想我總是可以找到我正在尋找手動使用for循環的視圖對象,這帶來了另一個問題。 Wrt的性能,最好是使用Mongo來做這樣的查詢,或者手動拉動整個文檔來循環收集?

+0

您不能僅獲取數組中的對象。您必須提取整個文檔。如果您想要自己創建子文檔,則需要使用聚合框架。 – cdbajorin

+0

@cdbajorin當你說「在他們自己的」,你的意思是不可能用_id值過濾掉我不想要的視圖?或者你的意思是我查找的查詢會給我一個類似'result.scenes [0] .views [0]'的結構嗎?我對後者很好。 – JSideris

回答

1

如果你的集合不是很大,而且這個操作比較少見,那麼用聚合框架就可以。但是如果這個操作頻繁且性能至關重要,那麼我會說應用級查詢。在任何情況下,這是你如何與聚集和$unwind做到這一點:

因此,如果這是您的收藏:

> db.col.find().pretty() 
{ 
    "_id" : ObjectId("57e6a5404897ec06f1c3d86f"), 
    "games" : [ 
     { 
      "_id" : "game1", 
      "scenes" : [ 
       { 
        "_id" : "scene1", 
        "views" : [ 
         { 
          "_id" : "view1" 
         } 
        ] 
       } 
      ] 
     } 
    ] 
} 
{ 
    "_id" : ObjectId("57e6a5d24897ec06f1c3d870"), 
    "games" : [ 
     { 
      "_id" : "game1", 
      "scenes" : [ 
       { 
        "_id" : "scene11", 
        "views" : [ 
         { 
          "_id" : "view111" 
         }, 
         { 
          "_id" : "view112" 
         }, 
         { 
          "_id" : "view113" 
         } 
        ] 
       }, 
       { 
        "_id" : "scene12", 
        "views" : [ 
         { 
          "_id" : "view121" 
         } 
        ] 
       } 
      ] 
     }, 
     { 
      "_id" : "game2", 
      "scenes" : [ 
       { 
        "_id" : "scene21", 
        "views" : [ 
         { 
          "_id" : "view211" 
         } 
        ] 
       } 
      ] 
     } 
    ] 
} 

,讓我們說,你想找到ID "view112",你可以在視圖這樣做:

db.col.aggregate([ 
    { $unwind: "$games"}, 
    { $unwind: "$games.scenes"}, 
    { $unwind: "$games.scenes.views"}, 
    { 
     $match: { 
      "games.scenes.views._id": "view112" 
     } 
    } 
]) 

,你會得到:

{ 
    "_id": ObjectId("57e6a5d24897ec06f1c3d870"), 
    "games": { 
     "_id": "game1", 
     "scenes": { 
      "_id": "scene11", 
      "views": { 
       "_id": "view112" 
      } 
     } 
    } 
} 
+0

這很酷。這是否需要這個特定的視圖ID不存在於任何其他場景中?有關爲此查詢創建索引的任何提示? – JSideris

+0

如果此視圖標識將顯示在其他位置,而您將在響應中獲取多個元素。話雖如此,你可以添加條件到'$ match'指令,以便專注於特定的遊戲,視圖,場景等。 至於你的其他問題,索引不會在這裏幫助,因爲匹配是在一個集合,這是不是原始集合,但所有'unwind'的結果,所以它不能被索引 –

+0

既然你知道視圖的ID首先,你應該在聚合的頂部有一個'$ match'來過濾只有那個視圖的遊戲。 – cdbajorin

0

我不明白這一點,喲你可以直接查詢

db.collection("games").findOne({"scenes.views._id":ObjectId(req.params.vid)},{_id:0,"scenes.$.views":1}); 

它應該刪除場景中的其他場景(雙關意圖)。但是,它仍然會爲您提供多個視圖,因爲$只能在任何表達式中使用一次。我認爲循環是關鍵。

我會建議反對聚合,他們是昂貴的。至於用查詢來實現這一點,或者獲取文檔並通過它循環。我肯定會通過查詢來實現它,您獲取的數據越少表現越好。

+0

你的意思是比較scenes.views._id與req.params.vid(反對sid,這是我用於場景的參數)? _id:0做什麼?請注意,視圖ID也是ObjectId對象。 – JSideris

+0

是的,它應該是req.params.vid,我的不好,更新了答案。如果它是對象ID,則保證它是唯一的。第二部分爲 –

+0

,_id:0告訴我們在結果中不需要_id。這是投影策略。你可以分別用1和0來設置你想要的和你不想要的。 –

相關問題