MongoDB聚合管道:在不知道字段值的情况下,按字段对数组元素进行分组



我有一系列足球比赛,形状是这样的:

{
_id: ObjectId("SomeUniqueMatchID"),
players: [
{ team: "Arsenal", name: "Saka", distanceRan: 8590},
{ team: "Arsenal", name: "Aubameyang", distanceRan: 9230}
// ...remaining players for both teams
],
timestamp: 129380193,
// other match info
}

我想查询奥巴梅扬和萨卡在一起比赛时的平均距离,无论他们在哪支球队,只要他们在同一支球队比赛

我了解球员场上的$unwind,然后是$match,最后使用$group来计算平均值,但在运行查询之前,当我不知道球队时,我不知道在$match条件上写什么。

Query1

  • 放松玩家
  • 比赛只保留两名球员的名字
  • match_idteam分组并按数组推送距离
  • 只匹配并保留大小为2的数组(这是关键,size=2,仅当这些球员同时参加了同一场比赛和同一支球队时(
    (如果您在示例中看到代码id=2,id=3将被忽略,因为这些球员从未同时参加过同一场赛和同一个球队(
  • uwnind距离(这里我们知道所有这些都是有效的距离(
  • null分组(所有集合1组(并平均距离(你不在乎哪场比赛、哪支球队或哪名球员,所以只保留关于平均距离的信息(

此处测试代码

aggregate(
[{"$unwind": {"path": "$players"}},
{"$match": 
{"$expr": 
{"$or": 
[{"$eq": ["$players.name", "Saka"]},
{"$eq": ["$players.name", "Aubameyang"]}]}}},
{"$group": 
{"_id": {"_id": "$_id", "team": "$players.team"},
"distances": {"$push": "$players.distanceRan"}}},
{"$match": {"$expr": {"$eq": [{"$size": "$distances"}, 2]}}},
{"$unwind": {"path": "$distances"}},
{"$group": {"_id": null, "avgDistanceRan": {"$avg": "$distances"}}},
{"$unset": ["_id"]}])

Query2

  • local它使用reduce,以及1场比赛中有1名球员,最多1次,最多1个团队(query1有效,即使这不是真的(
  • 为了保持这两个距离,我们只在团队相同且名称为二者之一的情况下添加距离数组
  • 再次只保持距离计数=2(以确保同一球队的同一场比赛中的两名球员(
  • 展开并按null分组,平均值如上

此处测试代码

aggregate(
[{"$set": 
{"players": 
{"$reduce": 
{"input": "$players",
"initialValue": {"team": null, "distances": []},
"in": 
{"$cond": 
[{"$and": 
[{"$or": 
[{"$eq": ["$$this.name", "Saka"]},
{"$eq": ["$$this.name", "Aubameyang"]}]},
{"$or": 
[{"$eq": ["$$value.team", null]},
{"$eq": ["$$value.team", "$$this.team"]}]}]},
{"team": "$$this.team",
"distances": 
{"$concatArrays": 
["$$value.distances", ["$$this.distanceRan"]]}},
"$$value"]}}}}},
{"$match": {"$expr": {"$eq": [{"$size": "$players.distances"}, 2]}}},
{"$unwind": {"path": "$players.distances"}},
{"$group": 
{"_id": null, "avgdistanceRan": {"$avg": "$players.distances"}}},
{"$unset": ["_id"]}])

我相信我理解你在寻找什么,但如果这是错误的,请告诉我。

正如您所说,您应该能够使用$match、$avg和$group的聚合管道。

您可以在这里查看查询的实时演示。

数据库

如果我们有以下数据库结构。。。

[
{
_id: ObjectId("123456789101819202122232"),
players: [
{
team: "Arsenal",
name: "Saka",
distanceRan: 8590
},
{
team: "Arsenal",
name: "Aubameyang",
distanceRan: 9230
}
],
timestamp: 129380193,

},
{
_id: ObjectId("123456789101819202999999"),
players: [
{
team: "Arsenal",
name: "Saka",
distanceRan: 7777
},
{
team: "NotArsenal",
name: "Aubameyang",
distanceRan: 9999
}
],
timestamp: 129399999,

}
]

查询

我们可以使用以下查询来计算平均值。

db.collection.aggregate([
{
$unwind: "$players"
},
{
$match: {
$or: [
{
"players.name": "Saka",
"players.team": "Arsenal"
},
{
"players.name": "Aubameyang",
"players.team": "Arsenal"
}
]
}
},
{
$group: {
_id: "$_id",
averageDistanceRan: {
$avg: "$players.distanceRan"
},
"players": {
$push: "$players"
}
}
},
{
"$match": {
"$expr": {
"$eq": [
{
"$size": "$players"
},
2
]
}
}
},
{
$project: {
_id: "$_id",
averageDistanceRan: 1
}
}
])

结果

这将给我们…

[
{
"_id": ObjectId("123456789101819202122232"),
"averageDistanceRan": 8910
}
]

相关内容

  • 没有找到相关文章

最新更新