蒙戈数据库 : how to use aggregate to build standings on nested fields

标签 mongodb aggregation-framework leaderboard

这是我的收藏:

[
  {userId: "u1", data: { score1: 1, score2: 2, score3: 3 }, day: 1},
  {userId: "u1", data: { score1: 1, score2: 0, score3: 0 }, day: 2}, 
  {userId: "u1", data: { score1: 5, score2: 3, score3: 2 }, day: 3},
  {userId: "u2", data: { score1: 2, score2: 5, score3: 1 }, day: 1}, 
  {userId: "u2", data: { score1: 1, score2: 1, score3: 6 }, day: 2},
  {userId: "u2", data: { score1: 3, score2: 5, score3: 3 }, day: 3},
  {userId: "u3", data: { score1: 4, score2: 1, score3: 1 }, day: 1},
  {userId: "u3", data: { score1: 0, score2: 1, score3: 1 }, day: 2},
  {userId: "u3", data: { score1: 0, score2: 1, score3: 10 }, day: 3}
]

我想构建以下排行榜表:

{
  score1: [
    {"u1": 7}, // sum of all score1 for u1
    {"u2": 6}, // sum of all score1 for u2
    {"u3": 4}, // sum of all score1 for u3
  ],
  score2: [
    {"u2": 11}, // sum of all score2 for u2
    {"u1": 5}, // sum of all score2 for u1
    {"u3": 3}, // sum of all score2 for u3
  ],
  score3: [
    {"u3": 12}, // sum of all score3 for u3
    {"u2": 10}, // sum of all score3 for u2
    {"u1": 5}, // sum of all score3 for u1
  ],
}

到目前为止,我可以按 userId 进行分组并计算其中 3 个的每个分数的总和:

db.myCollection.aggregate([
  {
    $group: {
      _id: "$userId",
      score1: { $sum: "$score1" },
      score2: { $sum: "$score2" },
      score3: { $sum: "$score3" }
    }
  }
])

这给了我:

[
  { 
    _id: "u1",
    score1: 7,
    score2: 5,
    score3: 5
  },
  { 
    _id: "u2",
    score1: 6,
    score2: 11,
    score3: 10
  },
  { 
    _id: "u3",
    score1: 4,
    score2: 3,
    score3: 12
  },
]

如何提取每种类型的分数并构建相应的排行榜?

提前致谢。

最佳答案

我首先会使用$objectToArray关于data场和 $unwind因此每个文档都有 1 个用户和 1 个分数。然后按userId分组和data.k (其中将包含“score1”、“score2”等)并计算总和。然后按分数名称重新组合并使用 k:userId, v:<score> 推送对象到一个数组。然后再次分组 null并推k:scoreName, v:<object with user scores>到一个数组。最后$arrayToObject将该数组转换为您想要的对象:

db.collection.aggregate([
    {$addFields: {data: {$objectToArray: "$data"}}},
    {$unwind: "$data"},
    {$group: {
         _id: {userId: "$userId", scoreName: "$data.k"},
         score: {$sum:"$data.v"}
    }},
    {$group: {
         _id:"$_id.scoreName",
         data:{$push:{k:"$_id.userId", v:"$score"}}
    }},
    {$group: {
         _id: null,
         scores:{$push:{k:"$_id", v:{$arrayToObject:"$data"}}}
    }},
    {$replaceRoot:{newRoot:{$arrayToObject:"$scores"}}}
])

Playground

关于蒙戈数据库 : how to use aggregate to build standings on nested fields,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60908336/

相关文章:

javascript - 对 Javascript 闭包案例感到困惑

javascript - 仅当文档中不存在提供者时才更新提供者数组并增加计数

mysql - MySQL 中的排行榜排名,查看器位于结果集中间

android - 谷歌排行榜提交分数失败

ios - 如何清除实时游戏中心排行榜数据?

database - 如何在 laravel 中自动将数据库从 mysql 更改为 mongodb

mongodb - 将 Spring 安全 ACL 与 spring-data-mongodb 结合使用

mongodb - 聚合错误: The field 'planet' must be an accumulator object

mongodb - Mongo 多级聚合组

javascript - 聚合或 Map Reduce 以创建规范化的 'Unique Paying Users Per Vendor'