我有一个收藏品将玩家的名字作为场地和他们的对手存储。名称和轮次作为嵌入文档播放。
"player1" : { "player2": 10,"player3": 25,"player4":8,"player5": 12}
这意味着"player1"
使用player2
进行了10轮,使用player3
进行了25轮,使用player4
进行了8轮,使用player5
进行了12轮。
最终,我想查询与特定球员进行最多轮次的前三名对手。我希望得到他们的名字和轮次,然后按轮次降序排列。
因此,对于player1
,我想返回"player3":25, "player5":12,"player2":10
现在我到目前为止最接近的是做db.collection.distinct("player1")
并且它将返回一个数组,其中嵌入的文档的顺序相同:
[ { "player2": 10,"player3": 25,"player4":8,"player5": 12} ]
答案 0 :(得分:1)
您可以使用3.4.4
版本并使用$objectToArray
& $arrayToObject
可在动态键和标签值对之间切换。
这是在不改变结构的情况下实现目标的一种方法。
第1阶段到第3阶段:将动态键转换为键值对,然后$match
上的player1
。
第4阶段到第7阶段:项目player
和opponent
并使用$objectToArray
将动态对手键转换为键值对,然后是$unwind
+ $sort
+ $limit
。
第8阶段& 9:将opponent
分组为键值对数组,然后$arrayToObject
将键值对转换为动态键。
db.collection.aggregate([
{$project: {keyvalarr: {$objectToArray: "$$ROOT"} }},
{$unwind:"$keyvalarr"},
{$match:{"keyvalarr.k":"player1"}},
{$project:{player:"$keyvalarr.k", opponent: {$objectToArray: "$keyvalarr.v"}},
{$unwind:"$opponent"},
{$sort:{"opponent.v":-1}},
{$limit:3},
{$group:{_id:null, player:{$first:"$player"}, opponent:{$push:"$opponent"}}},
{$project:{result: {$arrayToObject:"$opponent"}}}
])
对于较低版本,您必须将结构更改为类似的内容,并且可以使用索引。 (首选)
{player:"player1", opponent: [{player:"player2", rounds: 10},{player:"player3", rounds: 25}, {player:"player4", rounds: 8}, {player:"player5", rounds: 12}]}
您可以简化为以下聚合管道。
db.collection.aggregate([
{$match:{"player":"player1"}},
{$unwind:"$opponent"},
{$sort:{"opponent.rounds":-1}},
{$limit:3},
{$group:{_id:null, player:{$first:"$player"}, opponent:{$push:"$opponent"}}}
])