【问题标题】:MongoDB Query Array of Objects within Array of ObjectsMongoDB查询对象数组中的对象数组
【发布时间】:2017-03-04 02:23:53
【问题描述】:

我对 mongoDB 场景非常陌生,我正在尝试找出返回数组中底层对象的最佳方法,该数组包含在对象数组中的对象中。我知道这听起来令人困惑,所以让我向您展示我正在使用的内容。

{
    "_id": ObjectId("58b833a04953db3dd302102b"),
    "team": "Dragons",
    "rosters": [{
        "season": "2016-17",
        "players": [{
            "pitcher": "Oliver queen"
        }, {
            "catcher": "Slade Wilson"
        }]
    }, {
        "season": "2015-16",
        "players": [{
            "pitcher": "Joker"
        }, {
            "catcher": "Batman"
        }]
    }]
}

所以我的最终目标是:

  1. 根据位置(即“投手”)显示特定球队特定赛季的单个球员。例如,我想知道龙队 2015-16 赛季的投手是谁。

  2. 显示所有球员,根据他们的位置,在所有赛季为龙队。

  3. 为特定球队更新特定赛季中特定球员的姓名。 (例如,将 2016-17 赛季龙之队的“投手”从“奥利弗女王”更新为“绿箭侠”

这甚至是一个合理的查询吗?如果没有,我可以在哪里修复我的数据模型以提高性能?

提前致谢。

【问题讨论】:

    标签: mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    您的集合中有多个嵌套数组,而在 MongoDB 中,您不能使用多个 positional operator 对您的玩家集合执行更新操作。您应该为您的玩家定义一个name 字段和一个role 字段。您可以按如下方式构建数据:

    团队/赛季文件

    {
        "_id": ObjectId("58b99f08a7a2dfe1174e8eb9"),
        "team": "Dragons",
        "season": "2016-17",
        "players": [{
            "name": "Oliver queen",
            "role": "pitcher"
        }, {
            "name": "SomeOne",
            "role": "pitcher"
        }, {
            "name": "Slade Wilson",
            "role": "catcher"
        }]
    }
    

    因此,每个独特的团队/赛季对将拥有一份文件,因此:

    • 第一个文档:Dragons/2016-17
    • 第二个文档:Dragons/2015-17
    • 等等……

    根据他们的位置(即“投手”)显示单个玩家, 特定球队的特定赛季。例如我想知道谁 投手是 2015-16 赛季为龙队效力的。

    _如果你只有一个角色使用:

    db.players.find({
        "team": "Dragons",
        "season": "2016-17",
        "players.role": "pitcher"
    }, { "players.$": 1 })
    

    它只会返回第一个匹配pitcher角色的玩家:

    { "_id": ObjectId("58b99f08a7a2dfe1174e8eb9"), "players": [{ "name": "Oliver queen", "role": "pitcher" }] }
    

    _ 如果您可以按角色拥有多个玩家(如上面的模型中),请使用aggregation$filter 与匹配角色的players 数组:

    db.players.aggregate([{
        $match: {
            "team": "Dragons",
            "season": "2016-17",
            "players.role": "pitcher"
        }
    }, {
        $project: {
            players: {
                $filter: {
                    input: "$players",
                    as: "player",
                    cond: { $eq: ["$$player.role", "pitcher"] }
                }
            }
        }
    }])
    

    这给了你:

    { "_id": ObjectId("58b99f08a7a2dfe1174e8eb9"), "players": [{ "name": "Oliver queen", "role": "pitcher" }, { "name": "SomeOne", "role": "pitcher" }] }
    

    显示所有球员,根据他们的位置,在所有赛季的 龙队。

    使用players.role 聚合分组:

    db.players.aggregate([{
        $match: {
            "team": "Dragons"
        }
    }, {
        $unwind: "$players"
    }, {
        $group: {
            _id: "$players.role",
            players: {
                $push: "$players.name"
            }
        }
    }])
    

    这给了:

    { "_id": "catcher", "players": ["Slade Wilson", "Batman"] } { "_id": "pitcher", "players": ["Oliver queen", "SomeOne", "Joker"] }
    

    更新特定赛季中特定球员的姓名 特定的团队。 (例如,在 2016-17 赛季更新“投手”为 从“奥利弗女王”到“绿箭侠”的龙

    更新 positional parameter 匹配找到的项目:

    db.players.update({
        "team": "Dragons",
        "season": "2016-17",
        "players.name": "Oliver queen"
    }, {
        $set: {
            "players.$.name": "Green Arrow"
        }
    });
    

    球队/赛季/球员文件

    {
        "team": "Dragons",
        "season": "2016-17",
        "name": "Oliver queen",
        "role": "pitcher"
    }, {
        "team": "Dragons",
        "season": "2016-17",
        "name": "SomeOne",
        "role": "pitcher"
    }, {
        "team": "Dragons",
        "season": "2016-17",
        "name": "Slade Wilson",
        "role": "catcher"
    }
    

    每份文件都包含特定球队、特定赛季的一名球员

    根据他们的位置(即“投手”)显示单个玩家, 特定球队的特定赛季。例如我想知道谁 投手是 2015-16 赛季为龙队效力的。

    db.players.find({ "team": "Dragons", "season": "2016-17", "role": "pitcher" })
    

    显示所有球员,根据他们的位置,在所有赛季的 龙队。

    db.players.find({"team": "Dragons", "role": "pitcher"})
    

    更新特定赛季中特定球员的姓名 特定的团队。 (例如,在 2016-17 赛季更新“投手”为 从“奥利弗女王”到“绿箭侠”的龙

    db.players.update({
        "team": "Dragons",
        "season": "2016-17",
        "name": "Oliver queen"
    }, {
        $set: {
            "name": "Green Arrow"
        }
    })
    

    【讨论】:

    • 感谢您非常详细的回复!在构建我的模式时,我仍然试图摆脱关系思维。我将使用您发布的新结构并保留它作为将来自己的参考,以免再次犯同样的错误。
    • 请注意,如果您愿意,您还可以为每个唯一的team/season/player 使用 1 个文档,这样您就没有任何数组,并且更容易执行查找,更新、插入、不需要$unwind 等...如果你愿意,我可以将此解决方案添加到帖子中
    • 如果您不介意添加它。我也许可以自己弄明白,但为了以防万一,看看答题纸是没有坏处的。与数组设置相比,team/season/player 文档设置创建更多文档时性能会明显更好吗?
    • 我认为使用find 查询而不是aggregate 在您的集合中查找会更好。如果你想在players 中有更多的嵌套字段,如果你想稍后添加一些,使用过滤器和更新播放器内的嵌套元素也会更容易。但是如果可以的话,你可以继续使用带有玩家数组的模型
    • 我已经更新了我的帖子,注意最后一个模型不需要使用聚合,尤其是find
    猜你喜欢
    • 2021-09-24
    • 1970-01-01
    • 2012-05-05
    • 2014-05-13
    • 1970-01-01
    • 2020-07-27
    • 2020-10-30
    • 1970-01-01
    • 2021-11-14
    相关资源
    最近更新 更多