繁体   English   中英

MongoDB 结合每个文档的“最大值”和所有文档的“总和”的聚合

[英]MongoDB Aggregation combining both 'max' of EACH document and 'sum' of ALL documents

我正在记录高尔夫分数,现在正在尝试计算排行榜。 这是在 PHP 站点上使用的,所以我还需要翻译管道代码(之后)。

每个round文档都有一个holes数组:

{
  "playerName": "Tiger Woods", 
  "comp": {
    "name": "US Open 2021", 
    "courseId": "608952e3abebbd503ba6e115", 
    "scoringMethod": "Stableford", 
    "tees": "Blue", 
    "courseName": "MAGC Middle 9", 
    "roundNo": 2, 
    "id": {
      "$oid": "607019361c071256e4f0d0d5"
    }
  }, 
  "holes": [
    {
      "blue": 431, 
      "holeNett": 4, 
      "par": 4, 
      "holeGross": 5, 
      "no": 1, 
      "holeNettPoints": 2, 
      "yellow": 420, 
      "si": 2, 
      "holeStrokes": 1, 
      "white": 444, 
      "red": 399
    }, 
    {
      "blue": 335, 
      "holeNett": 5, 
      "par": 4, 
      "holeGross": 5, 
      "no": 2, 
      "holeNettPoints": 1, 
      "yellow": 320, 
      "si": 8, 
      "holeStrokes": 0, 
      "white": 350, 
      "red": 295
    }, 
    {
      "blue": 385, 
      "holeNett": 4, 
      "par": 4, 
      "holeGross": 5, 
      "no": 3, 
      "holeNettPoints": 2, 
      "yellow": 362, 
      "si": 4, 
      "holeStrokes": 1, 
      "white": 400, 
      "red": 343
    }, 
    {
      "blue": 161, 
      "holeNett": 3, 
      "par": 3, 
      "holeGross": 3, 
      "no": 4, 
      "holeNettPoints": 2, 
      "yellow": 144, 
      "si": 7, 
      "holeStrokes": 0, 
      "white": 180, 
      "red": 105
    }, 
    {
      "blue": 461, 
      "holeNett": 5, 
      "par": 5, 
      "holeGross": 6, 
      "no": 5, 
      "holeNettPoints": 2, 
      "yellow": 439, 
      "si": 1, 
      "holeStrokes": 1, 
      "white": 473, 
      "red": 418
    }, 
    {
      "blue": 330, 
      "holeNett": 4, 
      "par": 4, 
      "holeGross": 4, 
      "no": 6, 
      "holeNettPoints": 2, 
      "yellow": 300, 
      "si": 9, 
      "holeStrokes": 0, 
      "white": 337, 
      "red": 281
    }, 
    {
      "blue": 381, 
      "holeNett": 6, 
      "par": 4, 
      "holeGross": 6, 
      "no": 7, 
      "holeNettPoints": 0, 
      "yellow": 363, 
      "si": 5, 
      "holeStrokes": 0, 
      "white": 390, 
      "red": 290
    }, 
    {
      "blue": 152, 
      "holeNett": 3, 
      "par": 3, 
      "holeGross": 3, 
      "no": 8, 
      "holeNettPoints": 2, 
      "yellow": 140, 
      "si": 6, 
      "holeStrokes": 0, 
      "white": 167, 
      "red": 131
    }, 
    {
      "blue": 366, 
      "holeNett": 3, 
      "par": 4, 
      "holeGross": 4, 
      "no": 9, 
      "holeNettPoints": 3, 
      "yellow": 344, 
      "si": 3, 
      "holeStrokes": 1, 
      "white": 396, 
      "red": 327
    }
  ], 
  "playerId": "609d0993906429612483cea0", 
  "holeCount": 9, 
  "countbackScores": [
    16, 
    11, 
    5, 
    2
  ], 
  "team": "magc", 
  "date": "2021-05-20T23:00:00+00:00", 
  "computedScore": 16, 
  "computedThru": 9, 
  "_id": {
    "$oid": "60a6aa828078924a6065dc9e"
  }
}

我有一个聚合管道,可以找到每个洞的最高或最低(取决于比赛规则)分数。 我不得不$unwind子数组,为每个播放的洞生成一个管道文件。 通常这意味着每个玩家需要 18 个文件或 9 个半轮文件。 还要注意的是,每round都可以在不同的comp.courseId上进行(我的初始比赛中有 3 门课程) - 所以这些课程也需要分组,因此它目前在我的$match过滤器中。

我可以在同一管道中计算最终管道output的累计总数,同时保留以前的文件吗?

[{$match: {
    "comp.id" : ObjectId('600019361c071256e4f0d0d5'),
    "playerId" : "600d0993906429612483cea0",
    "comp.courseId" : "600955aaabebbd503ba6e116"
}
}, 
{$unwind: {
  path : "$holes"
}}, 
{$group: {
  _id: "$holes.no",
  hole: {
    $max: "$holes"
  }
}}, 
{$set: {
  "total": { "$sum" : "$hole.holeNettPoints" }
}}, 
{$sort: {
  "hole.no": 1
}
}]

$set管道是我正在测试的阶段。 但这仅对来自单个文档的holeNettPoints字段求和,因此与每个文档中的此值相同。

我不认为我可以对所有这些文档再做一个$group ,就像在我的 PHP 页面上一样,我需要其他每个孔字段来构建 HTML 表。 但它按该轮的累计总数排序。 所以我尝试使用$set添加一个字段。 这个对吗?

这将返回每个打球的文档(我当前的数据为 9 个,通常为 18 个用于整轮高尔夫)。 我想获得所有 9 个洞的累积holeNettPoints总数,以及每个holeNettPoints上每个球员的每洞$max courseId 一些结构:

playerId = 123456
courseId = abcdef
total = 18
holes = (
    ([no] => 1, [holeNettPoints] => 2),
    ([no] => 2, [holeNettPoints] => 2),
    ([no] => 3, [holeNettPoints] => 3),
    ([no] => 4, [holeNettPoints] => 1),
    ([no] => 5, [holeNettPoints] => 2),
    ([no] => 6, [holeNettPoints] => 2),
    ([no] => 7, [holeNettPoints] => 2),
    ([no] => 8, [holeNettPoints] => 2),
    ([no] => 9, [holeNettPoints] => 2),
)

理想情况下,结果将返回单个文档,然后我将能够删除playerId $match过滤器,以便它适用于将在每个组合中玩的许多玩家。

我希望 MongoDB 使用聚合来返回格式化和排序的结果,因此 PHP 可以循环遍历它的结果。

  • $group by playerId , courseIdno并获得最大的holeNettPoints
  • $group by playerId并构造noholeNettPointsholes数组,并获得所有holeNettPoints的总数
db.collection.aggregate([
  {
    $match: {
      "comp.id": ObjectId("607019361c071256e4f0d0d5"),
      "playerId": "609d0993906429612483cea0",
      "comp.courseId": "608952e3abebbd503ba6e115"
    }
  },
  { $unwind: { path: "$holes" } },
  {
    $group: {
      _id: {
        playerId: "$playerId",
        courseId: "$comp.courseId",
        no: "$holes.no"
      },
      holeNettPoints: { $max: "$holes.holeNettPoints" }
    }
  },
  {
    $group: {
      _id: "$_id.playerId",
      courseId: { $first: "$_id.courseId" },
      holes: {
        $push: {
          no: "$_id.no",
          holeNettPoints: "$holeNettPoints"
        }
      },
      total: { $sum: "$holeNettPoints" }
    }
  }
])

操场


PHP 语法:

$query = [
  [
    '$match' => [
      'comp.id' => ObjectId("607019361c071256e4f0d0d5"),
      'playerId' => "609d0993906429612483cea0",
      'comp.courseId' => "608952e3abebbd503ba6e115"
    ]
  ],
  [ '$unwind' => [ 'path' => '$holes' ] ],
  [
    '$group' => [
      '_id' => [
        'playerId' => '$playerId',
        'courseId' => '$comp.courseId',
        'no' => '$holes.no'
      ],
      'holeNettPoints' => [ '$max' => '$holes.holeNettPoints' ]
    ]
  ],
  [
    '$group' => [
      '_id' => '$_id.playerId',
      'courseId' => [ '$first' => '$_id.courseId' ],
      'holes' => [
        '$push' => [
          'no' => '$_id.no',
          'holeNettPoints' => '$holeNettPoints'
        ]
      ],
      'total' => [ '$sum' => '$holeNettPoints' ]
    ]
  ]
]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM