我如何投影5个计数并在MongoDB中概括其余的计数?

发布于 2025-02-05 07:26:44 字数 631 浏览 2 评论 0 原文

我有以下文档:

_id: "Team 1"
count: 1200

_id: "Team 2"
count: 1170

_id: "Team 3"
count: 1006

_id: "Team 4"
count: 932

_id: "Team 5"
count: 931

_id: "Team 6"
count: 899

_id: "Team 7"
count: 895

列表已经对其进行整理,并且所有内容都需要根据计数将其投影为前5名的数组,然后将其余的应求和为“其他”。如果可能的话,我还要添加列表中每个元素的百分比由全部计数构成。像这样:

[
  {"name":"Team 1", "count":1200, "percent":25},
  {"name":"Team 2", "count":1170,"percent":15},
  {"name":"Team 3", "count":1006,"percent":10},
  {"name":"Team 4", "count":932,"percent":5},
  {"name":"Team 5", "count":931,"percent":5},
  {"name":"Other", "count":1794, "percent":40}]
]

I have the following documents:

_id: "Team 1"
count: 1200

_id: "Team 2"
count: 1170

_id: "Team 3"
count: 1006

_id: "Team 4"
count: 932

_id: "Team 5"
count: 931

_id: "Team 6"
count: 899

_id: "Team 7"
count: 895

The list is already sorted and everything, I just need to project this as an array of top 5 based on count and then the rest should be summed as 'others'. If possible I'd like to also add the percentage that each element in the list makes up of the full count. Like this:

[
  {"name":"Team 1", "count":1200, "percent":25},
  {"name":"Team 2", "count":1170,"percent":15},
  {"name":"Team 3", "count":1006,"percent":10},
  {"name":"Team 4", "count":932,"percent":5},
  {"name":"Team 5", "count":931,"percent":5},
  {"name":"Other", "count":1794, "percent":40}]
]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

面犯桃花 2025-02-12 07:26:44

查询

  • 添加排序级
  • $ setWindowfields 进行排序,并通过 null 与3个累加器
    • 按下前5个文档不变
    • 总计其余的计数(等级> 5)
    • 总和
  • $ map 将计数与5个顶级文档的总和分开,以获取
  • 百分比其余文档的百分比
  • 放松并取代根部,并使用具有数量和百分比的文档

(将鼠标放在每个阶段的末端,以查看阶段进出)

aggregate(
[{"$setWindowFields": 
   {"output": {"rank": {"$rank": {}}}, "sortBy": {"count": -1}}},
 {"$group": 
   {"_id": null,
    "top5": 
     {"$push": {"$cond": [{"$lte": ["$rank", 5]}, "$ROOT", "$REMOVE"]}},
    "other": {"$sum": {"$cond": [{"$lte": ["$rank", 5]}, 0, "$count"]}},
    "all": {"$sum": "$count"}}},
 {"$project": 
   {"_id": 0,
    "docs": 
     {"$concatArrays": 
       [{"$map": 
           {"input": "$top5",
            "in": 
             {"name": "$this._id",
              "count": "$this.count",
              "percentage": 
               {"$multiply": [{"$divide": ["$this.count", "$all"]}, 100]}}}},
         [{"name": "other",
            "count": "$other",
            "percentage": 
             {"$multiply": [{"$divide": ["$other", "$all"]}, 100]}}]]}}},
 {"$unwind": "$docs"}, {"$replaceRoot": {"newRoot": "$docs"}}])

Query

  • $setWindowFields to sort and add the sort-rank to each document
  • group by null with 3 accumulators
    • push the first 5 documents unchanged
    • sum the count of the rest (rank>5)
    • total sum
  • $map to divide the counts with the total sum for the 5 top documents, to get the percentage also
  • add also the percentage for the rest of documents
  • unwind and replace the root, with those documents that have count and percentage

Playmongo (put the mouse at the end of each stage to see the stage in and out)

aggregate(
[{"$setWindowFields": 
   {"output": {"rank": {"$rank": {}}}, "sortBy": {"count": -1}}},
 {"$group": 
   {"_id": null,
    "top5": 
     {"$push": {"$cond": [{"$lte": ["$rank", 5]}, "$ROOT", "$REMOVE"]}},
    "other": {"$sum": {"$cond": [{"$lte": ["$rank", 5]}, 0, "$count"]}},
    "all": {"$sum": "$count"}}},
 {"$project": 
   {"_id": 0,
    "docs": 
     {"$concatArrays": 
       [{"$map": 
           {"input": "$top5",
            "in": 
             {"name": "$this._id",
              "count": "$this.count",
              "percentage": 
               {"$multiply": [{"$divide": ["$this.count", "$all"]}, 100]}}}},
         [{"name": "other",
            "count": "$other",
            "percentage": 
             {"$multiply": [{"$divide": ["$other", "$all"]}, 100]}}]]}}},
 {"$unwind": "$docs"}, {"$replaceRoot": {"newRoot": "$docs"}}])
水水月牙 2025-02-12 07:26:44

使用 $ facet 进行此操作的另一种方法,因为 $ setWindowfields 仅与mongodb v5或更高版本一起使用

mongoplayground

db.collection.aggregate([
    { $sort: { count: -1 } },
    {
      "$facet": {
        others: [
          { "$skip": 5 },
          {
            "$group": {
              "_id": "others",
              "count": { "$sum": "$count" }
            }
          }
        ],
        top5: [ { "$limit": 5 } ]
      }
    },
    {
        "$project": { result: { "$concatArrays": [ "$others", "$top5" ] } }
    },
    {
        "$addFields": { totalCount: { "$sum": "$result.count" } }
    },
    { $unwind: "$result" },
    {
      $project: {
        _id: "$result._id",
        count: "$result.count",
        percent: {
          $round: [
            { "$multiply": [ { $divide: [ "$result.count", "$totalCount" ] }, 100 ] },
            0
          ]
        }
      }
    }
  ])

another way to do it using $facet since $setWindowFields only works with mongodb v5 or later

mongoPlayground

db.collection.aggregate([
    { $sort: { count: -1 } },
    {
      "$facet": {
        others: [
          { "$skip": 5 },
          {
            "$group": {
              "_id": "others",
              "count": { "$sum": "$count" }
            }
          }
        ],
        top5: [ { "$limit": 5 } ]
      }
    },
    {
        "$project": { result: { "$concatArrays": [ "$others", "$top5" ] } }
    },
    {
        "$addFields": { totalCount: { "$sum": "$result.count" } }
    },
    { $unwind: "$result" },
    {
      $project: {
        _id: "$result._id",
        count: "$result.count",
        percent: {
          $round: [
            { "$multiply": [ { $divide: [ "$result.count", "$totalCount" ] }, 100 ] },
            0
          ]
        }
      }
    }
  ])
懵少女 2025-02-12 07:26:44

如果您的MongoDB版本5.0或更高版本,则可以使用 $ setWindowfields 在@takis中的好答案。否则,您可以 group $ slice $ redion 您的答案方式:

  1. $ sort 顶部和组的最高计数将它们全部放入一个数组中,称为 ash all $ sum up。
  2. $ slice 所有数组仅保留顶部N。
  3. $ redaim the the the the the top n可以将它们总结。
  4. 其他添加到带有Count sum-sum(topn)
  5. $ untind 和格式
db.collection.aggregate([
  {$sort: {count: -1}},
  {$group: {_id: null, all: {$push: "$ROOT"}, sum: {$sum: "$count"}}},
  {$project: {_id: null, sum: 1,  res: {$slice: ["$all", 5]}}},
  {$project: {sum: 1,  res: 1, topN: {
        $reduce: {
          input: "$res",
          initialValue: 0,
          in: {$add: ["$value", "$this.count"]}
        }
      }
    }
  },
  {
    $project: {_id: 0, sum: 1, res: {
      $concatArrays: [
        [{_id: "other",  count: {$subtract: ["$sum", "$topN"]}}],
          "$res"
        ]
      }
    }
  },
  {$unwind: "$res"},
  {$project: {_id: "$res._id", count: "$res.count",
     percent: {  $round: [{$multiply: 
        [{$divide: ["$res.count", "$sum"]}, 100]}, 0]
      }
    }
  }
])

<代码> <代码> ) 的顶部N数组中mongoplayground.net/p/ckttf9iblt0“ rel =“ nofollow noreferrer”>游乐场示例

If you have mongoDB version 5.0 or higher you can use $setWindowFields like in @Takis nice answer. Otherwise, you can group, $slice and $reduce your way to the answer:

  1. $sort to have the highest count on top and group to put them all in one array called all and to $sum up.
  2. $slice the all array to keep only the top N.
  3. $reduce the top N to sum them up.
  4. Add the others to the top N array with count sum-sum(topN)
  5. $unwind and format
db.collection.aggregate([
  {$sort: {count: -1}},
  {$group: {_id: null, all: {$push: "$ROOT"}, sum: {$sum: "$count"}}},
  {$project: {_id: null, sum: 1,  res: {$slice: ["$all", 5]}}},
  {$project: {sum: 1,  res: 1, topN: {
        $reduce: {
          input: "$res",
          initialValue: 0,
          in: {$add: ["$value", "$this.count"]}
        }
      }
    }
  },
  {
    $project: {_id: 0, sum: 1, res: {
      $concatArrays: [
        [{_id: "other",  count: {$subtract: ["$sum", "$topN"]}}],
          "$res"
        ]
      }
    }
  },
  {$unwind: "$res"},
  {$project: {_id: "$res._id", count: "$res.count",
     percent: {  $round: [{$multiply: 
        [{$divide: ["$res.count", "$sum"]}, 100]}, 0]
      }
    }
  }
])

Playground example

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文