如何在MongoDB中找到嵌套在数组深处的对象?

时间:2016-09-24 15:00:05

标签: node.js 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进行这样的查询,还是通过拉动整个文档循环收集来手动?

2 个答案:

答案 0 :(得分: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"
            }
        }
    }
}

答案 1 :(得分:0)

我没有得到它,您可以直接查询

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

它应该从场景中删除其他场景(双关语)。但是,它仍然会为您提供多个视图,因为$只能在任何表达式中使用一次。在那里,我认为循环是关键。

我建议反对聚合,它们很昂贵。至于用查询来实现这个或者获取文档并循环遍历它。我肯定会通过查询来实现它,你获取的数据越少,性能就越好。