基于条件的文档中各个字段的总计数

时间:2018-06-30 17:54:36

标签: javascript mongodb mongoose

我希望能够获取某些值,并根据哪个键具有特定ID来获取这些值在集合中的次数。例如,这是来自游戏日志集合

的单个文档的示例
{
    "_id": "5af88940b73b2936dcb6dfdb",
    "date": "2018-05-13T18:51:44.548Z",
    "playerOne": "5af888d0b73b2936dcb6dfd3",
    "playerOneThrew": "Scissors",
    "playerTwo": "5af88918b73b2936dcb6dfd7",
    "playerTwoThrew": "Rock",
    "winner": "5af88918b73b2936dcb6dfd7",
     "__v": 0
}

我希望能够根据玩家ID(可以是playerOne或可以是playerTwo)进行查询,并在每次比赛中都拉回玩家扔出的手牌。从本质上讲,我希望能够通过玩家ID来获得所有游戏的所有掷出的手(石头,纸,剪刀)的总数。

是否可以汇总集合中所有文档的每个“掷手”值的计数并返回类似

的方式
{
    "player": "5af888d0b73b2936dcb6dfd3",
    "Rock": 3,
    "Paper": 6,
    "Scissors": 12
}

我的想法是根据id匹配playerOne ||来设置一个变量。然后,playerTwo在switch语句中使用该变量,在该语句中汇总“ rock”,“ paper”,“ scissors”的计数。问题是我对使用MongoDB并不陌生,而且我难以理解此类查询的正确语法。

我现在在这里

GameLogs.aggregate(
  [
    {
      $let: {
        vars: {
          playerThrew: {
            $cond: {
              if: {
                $eq: { playerOne: id },
              }
              }, then: playerOneThrew, else: playerTwoThrew
            }
        }
      }
    },
    {
      $switch: {
        branches: [
          { case: { $eq: 'Rock' }, then: { $count: 'Rock' } },
          { case: { $eq: 'Paper' }, then: { $count: 'Paper' } },
          { case: { $eq: 'Scissors' }, then: { $count: 'Scissors' } },
        ]
      }
    }
  ]
)

伪代码

if playerOne == id
  playerThrew = playerOneThrows
else if playerTwo == id
  playerThrew = playerTwoThrows

switch playerThrew {
  case 'rock':
    rockCount++
    break
  case 'paper':
    paperCount++
    break
  case 'scissors':
    scissorsCount++
    break
}

return {
  player_id: id,
  rock: rockCount,
  paper: paperCount,
  scissors: scissorCount
}

任何见识都会受到赞赏。

2 个答案:

答案 0 :(得分:1)

RadosławMiernik的答案很好,但仍然需要$match,因为OP只想获取特定玩家的数据。

可以说playerId是需要数据的播放器的_id

下面的代码应该起作用,并给出预期的结果

collection.aggregate([
  {$project: {
    player: [
      {id: '$playerOne', threw: '$playerOneThrew'},
      {id: '$playerTwo', threw: '$playerTwoThrew'}
    ],
  }},
  {$unwind: '$player'},
  {$match : { 
    "player.id" : playerId 
  }},
  {$group: {
    _id: '$player.id',
    player : {$first : "$player.id},
    Paper:    {$sum: {$cond: [{$eq: ['$player.threw', 'Paper'   ]}, 1, 0]}},
    Rock:     {$sum: {$cond: [{$eq: ['$player.threw', 'Rock'    ]}, 1, 0]}},
    Scissors: {$sum: {$cond: [{$eq: ['$player.threw', 'Scissors']}, 1, 0]}}
  }}
])

这将提供您正在寻找的确切结果,以及一个额外的_id字段。

{
    "_id": "5af888d0b73b2936dcb6dfd3",
    "player": "5af888d0b73b2936dcb6dfd3",
    "Rock": 3,
    "Paper": 6,
    "Scissors": 12
}

答案 1 :(得分:0)

您可以将每个文档分为两个标准化文档,然后轻松将它们分组:

collection.aggregate([
  {$match: {
    $or: [
      {playerOne: playerId},
      {playerTwo: playerId}
    ]
  },
  {$project: {
    player: [
      {id: '$playerOne', threw: '$playerOneThrew'},
      {id: '$playerTwo', threw: '$playerTwoThrew'}
    ],
  }},
  {$unwind: '$player'},
  {$match: {'player.id': playerId},
  {$group: {
    _id: '$player.id',
    Paper:    {$sum: {$cond: [{$eq: ['$player.threw', 'Paper'   ]}, 1, 0]}},
    Rock:     {$sum: {$cond: [{$eq: ['$player.threw', 'Rock'    ]}, 1, 0]}},
    Scissors: {$sum: {$cond: [{$eq: ['$player.threw', 'Scissors']}, 1, 0]}}
  }}
])

编辑::添加了$match阶段以仅针对给定玩家有效地过滤分数。