如何计算MongoDB中重复的数组元素

时间:2016-10-24 02:50:45

标签: mongodb aggregation-framework

我对如何实现这一点感到有些困惑,希望有人能帮助我解决这个问题!

我的文件看起来像这样:

{
    "_id" : NumberLong("1213477"),
    "players" : [
        {
            "acc_id" : 1,
            "cards" : [
                {
                    "id" : 112,
                    "l" : 3
                },
                {
                    "id" : 121,
                    "l" : 6
                },
                {
                    "id" : 123
                },
                {
                    "id" : 126
                },
                {
                    "id" : 130,
                    "l" : 8
                },
                {
                    "id" : 139,
                    "l" : 6
                },
                {
                    "id" : 103,
                    "l" : 6
                },
                {
                    "id" : 111
                }
            ]
        },
        {
            "acc_id" : 52,
            "cards" : [
                {
                    "id" : 112,
                    "l" : 2
                },
                {
                    "id" : 121,
                    "l" : 5
                },
                {
                    "id" : 123
                },
                {
                    "id" : 132
                },
                {
                    "id" : 139,
                    "l" : 5
                },
                {
                    "id" : 104,
                    "l" : 2
                },
                {
                    "id" : 108,
                    "l" : 8
                },
                {
                    "id" : 108,
                    "l" : 1
                }
            ]
        }
    ]
}

所以,这个游戏中有两个玩家,每个玩家都有8张牌。我想运行一些查询,并找出有多少人使用相同的确切卡。最后,我应该能够列出最受欢迎的套牌。 (每张卡都有特定用途)

非常感谢任何帮助......谢谢!

1 个答案:

答案 0 :(得分:2)

如果我理解不当,mongodb aggregation framework以及$unwind$group$match管道和$sum运算符应该适合你。
因此,基于以下集合(非常类似于您上面发布的):

db.game_players.insert({    
    "players" : [
        {
            "acc_id" : 1,
            "cards" : [
                {"id" : 112, "l" : 3 }, 
                {"id" : 121, "l" : 6 }, 
                {"id" : 123 },
                {"id" : 126 },
                {"id" : 130, "l" : 8},
                {"id" : 139, "l" : 6 },
                {"id" : 103, "l" : 6 },
                {"id" : 111 }
            ]
        },
        {
            "acc_id" : 52,
            "cards" : [
                {"id" : 112, "l" : 2 },
                {"id" : 121, "l" : 5 },
                {"id" : 123 },
                {"id" : 132 },
                {"id" : 139, "l" : 5 },
                {"id" : 104, "l" : 2 },
                {"id" : 108, "l" : 8 },
                {"id" : 108, "l" : 1 }
            ]
        }
    ]
})

第1步:放松球员:

db.game_players.aggregate([{$unwind: '$players'}])

它从输入文档解构数组字段,以输出每个元素的文档。输出是这样的:

{
    "_id" : ObjectId("580d792676d77d5928600787"),
    "players" : {
        "acc_id" : 1,
        "cards" : [
            {
                "id" : 112,
                "l" : 3
            },
            {
                "id" : 121,
                "l" : 6
            },
            {
                "id" : 123
            },
            {
                "id" : 126
            },
            {
                "id" : 130,
                "l" : 8
            },
            {
                "id" : 139,
                "l" : 6
            },
            {
                "id" : 103,
                "l" : 6
            },
            {
                "id" : 111
            }
        ]
    }
}
{
    "_id" : ObjectId("580d792676d77d5928600787"),
    "players" : {
        "acc_id" : 52,
        "cards" : [
            {
                "id" : 112,
                "l" : 2
            },
            {
                "id" : 121,
                "l" : 5
            },
            {
                "id" : 123
            },
            {
                "id" : 132
            },
            {
                "id" : 139,
                "l" : 5
            },
            {
                "id" : 104,
                "l" : 2
            },
            {
                "id" : 108,
                "l" : 8
            },
            {
                "id" : 108,
                "l" : 1
            }
        ]
    }
}

正如您所看到的,现在每个播放器都是文档而不是数组元素。

第2步:按卡分组

在下一阶段,我们将用卡片添加组管道分组:

db.game_players.aggregate([{
    $unwind: '$players'
}, {
    '$group': {
        _id: {
            'card': '$players.cards.id'
        }
    }
}]) {
    "_id": {
        "card": [112, 121, 123, 132, 139, 104, 108, 108]
    }
} {
    "_id": {
        "card": [112, 121, 123, 126, 130, 139, 103, 111]
    }
}

哪个输出:

{ "_id" : { "card" : [ 112, 121, 123, 132, 139, 104, 108, 108 ] } }
{ "_id" : { "card" : [ 112, 121, 123, 126, 130, 139, 103, 111 ] } }

请注意,cards键已添加到分组中。那是因为我们需要在下一阶段引用它。

步骤3:放松并再次分组,并将流行的(重复的?)卡片相加

db.game_players.aggregate([{
    $unwind: '$players'
}, {
    '$group': {
        _id: {
            'card': '$players.cards.id'
        }
    }
}, {
    '$unwind': '$_id.card'
}, {
    '$group': {
        _id: '$_id.card',
        'cards_count': {
            '$sum': 1
        }
    }
}])

目前我们有每张卡的总数。见下面的输出:

{ "_id" : 111, "cards_count" : 1 }
{ "_id" : 103, "cards_count" : 1 }
{ "_id" : 126, "cards_count" : 1 }
{ "_id" : 123, "cards_count" : 2 }
{ "_id" : 108, "cards_count" : 2 }
{ "_id" : 112, "cards_count" : 2 }
{ "_id" : 104, "cards_count" : 1 }
{ "_id" : 139, "cards_count" : 2 }
{ "_id" : 132, "cards_count" : 1 }
{ "_id" : 130, "cards_count" : 1 }
{ "_id" : 121, "cards_count" : 2 }

现在你快到了!

步骤4:选择计数大于或等于2的卡:

db.game_players.aggregate([{
    $unwind: '$players'
}, {
    '$group': {
        _id: {
            'card': '$players.cards.id'
        }
    }
}, {
    '$unwind': '$_id.card'
}, {
    '$group': {
        _id: '$_id.card',
        'cards_count': {
            '$sum': 1
        }
    }
}, {
    '$match': {
        cards_count: {
            '$gte': 2
        }
    }
}])

最终输出是:

{ "_id" : 123, "cards_count" : 2 }
{ "_id" : 108, "cards_count" : 2 }
{ "_id" : 112, "cards_count" : 2 }
{ "_id" : 139, "cards_count" : 2 }
{ "_id" : 121, "cards_count" : 2 }