我正在尝试撰写MongoDB查询...
我的目标是按country
按rating
排序,然后返回 每个国家/地区的第n个评级玩家列出的玩家记录列表(所以评分最高,或者评分最高的第三名)。
我已经实现了第一部分:
db.getCollection('players').find( { event: 'open' }).sort({ country: 1, rating: -1 });
以下是两个国家的样本,每个国家有三名玩家,按评级排序:
第一队:
{
"id" : 400041,
"name" : "Adams Michael",
"rating" : 2727,
"country" : "England",
"event" : "open"
},
{
"id" : 404853,
"name" : "McShane Luke J",
"rating" : 2671,
"country" : "England",
"event" : "open",
},
{
"id" : 400025,
"name" : "Short Nigel D",
"rating" : 2666,
"country" : "England",
"event" : "open"
}
第二组:
{
"id": 4101588,
"name": "Kramnik Vladimir",
"rating": 2808,
"country": "Russia",
"event": "open"
},
{
"id": 4126025,
"name": "Grischuk Alexander",
"rating": 2784,
"country": "Russia",
"event": "open"
},
{
"id": 14109603,
"name": "Karjakin Sergey",
"rating": 2769,
"country": "Russia",
"event": "open"
}
我希望我的查询返回以下对象:
(因为这是评价最高的两个)
我希望我的查询也允许我查询第二高的评分:
答案 0 :(得分:8)
这是使用4阶段聚合管道
的方法project
与$arrayElemAt
一起获得各个国家/地区ith
评分的玩家再次使用项目为您提供所需格式的对象
db.getCollection('players').aggregate(
{
$sort: {country: 1, rating: -1}
},
{
$group: {
_id: "$country",
players: {$push: {name: "$name", rating: "$rating", event: "$event"}}
}
},
{
$project: {
player: {$arrayElemAt: ["$players", iTH_RATING]}
}
},
{
$project: {
name: "$player.name",
rating: "$player.rating",
event: "$player.event"
}
})
请参阅下面的屏幕抓取2nd Highest Rated Players
。由于这些是0-indexed
,因此查询中的iTH_RATING
变量将替换为1.要获得评分最高的玩家,请将其替换为0,依此类推。
答案 1 :(得分:1)
您可以通过聚合执行此操作。如果您在 $ group 阶段之前 $ sort ,则可以使用 $ first 从每个组(国家/地区)的第一个相关文档中检索数据:
db.getCollection('players').aggregate([
{
$sort: { country: 1, rating: -1 }
},
{
$group:{
_id: "$country",
"highest_rated": { "$first": "$name" }
}
}
]);
如果您想要匹配文档中的所有归属(不仅仅是玩家名称),您可以使用$$ ROOT:
db.getCollection('players').aggregate([
{
$sort: { country: 1, rating: -1 }
},
{
$group:{
_id: "$country",
"highest_rated": { "$first": "$$ROOT" }
}
}
]);
答案 2 :(得分:1)
您可以使用$skip
和$limit
使用var map = function map(){
emit(this.country, this);
};
var reduce = function(key, values){
var position_to_return = 1; // change here to 0 to return the first rated player for certain country
var sorted_values = values.sort(function(first, second) {
return second.rating - first.rating;
})
return key, sorted_values[position_to_return];
};
db.runCommand({"mapReduce":"players", map:map, reduce:reduce, out:{replace:"players2"}, query:{ "event": "open" }})
和{
"_id" : "England",
"value" : {
"_id" : ObjectId("57bb093c6124c1a9d8be905d"),
"id" : 404853,
"name" : "McShane Luke J",
"rating" : 2671,
"country" : "England",
"event" : "open"
}
}
{
"_id" : "Russia",
"value" : {
"_id" : ObjectId("57bb093c6124c1a9d8be9060"),
"id" : 4126025,
"name" : "Grischuk Alexander",
"rating" : 2784,
"country" : "Russia",
"event" : "open"
}
}
,在他的评论中使用多个查询,每个国家/地区一个查询。
您可以使用map-reduce,而不是在1'查询'中获得预期结果(但请记住,map-reduce不适合实时查询,可能是非常慢的操作,但这很大程度上取决于你的数据大小)。
在地图功能中,使用键作为国家/地区来触发文档。在reduce功能中,根据评级从同一国家/地区对玩家进行排序,并仅从排名中的所需位置返回文档(玩家):
Option Explicit
Function CAGR2(rng As Range) As Double
Dim cell As Variant
Dim n As Integer
CAGR2 = 1
n = 0
For Each cell In rng
CAGR2 = CAGR2 * (cell.Value + 1)
n = n + 1
Next cell
CAGR2 = CAGR2 ^ (1 / (n / 12))
End Function
输出,当返回每个国家的第二名球员时:
n