2016-09-24 34 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来设置你想要的和你不想要的。 –

相关问题