mongodb - 如何实现 $bucket 按多个字段分组

标签 mongodb aggregation-framework

起初bucket按年龄和边界[0,20,30,40,50,200]

db.user.aggregate(
    {$project: {_id:0, age:{$subtract:[{$year:new Date()}, {$year:"$birthDay"}]} } },
    {$bucket:{
        groupBy:"$age",
        boundaries:[0,20,30,40,50,200]
    }},
    { $project:{ _id:0,age:"$_id",count:1 } }
)

得到以下结果

{ "count" : 5, "age" : 20 }
{ "count" : 1, "age" : 30 }

然后我想进一步统计每个城市的每个年龄段的数量

{ city : "SH", age: 20, count: 2 }
{ city : "BJ", age: 20, count: 3 }
{ city : "BJ", age: 30, count: 1 }

那么在这种情况下如何实现呢?

此外

db.user.aggregate(
    { $project: {_id:0, city:1, age:{$subtract:[{$year:new Date()}, {$year:"$birthDay"}]} } },
    { $group: { _id:"$city",ages:{$push:"$age"} } },
    { $project: {_id:0, city:"$_id",ages:1} }
)

{ "city" : "SH", "ages" : [ 26, 26 ] }
{ "city" : "BJ", "ages" : [ 27, 26, 26, 36 ] }

最佳答案

你说的其实是用$switch实现的, 在常规 $group 内阶段:

db.user.aggregate([
  { "$group": {
    "_id": {
      "city": "$city",
      "age": {
        "$let": {
          "vars": { 
            "age": { "$subtract" :[{ "$year": new Date() },{ "$year": "$birthDay" }] }
          },
          "in": {
            "$switch": {
              "branches": [
                { "case": { "$lt": [ "$$age", 20 ] }, "then": 0 },
                { "case": { "$lt": [ "$$age", 30 ] }, "then": 20 },
                { "case": { "$lt": [ "$$age", 40 ] }, "then": 30 },
                { "case": { "$lt": [ "$$age", 50 ] }, "then": 40 },
                { "case": { "$lt": [ "$$age", 200 ] }, "then": 50 }
              ]
            }
          }
        }
      }
    },
    "count": { "$sum": 1 }
  }}
])

结果:

{ "_id" : { "city" : "BJ", "age" : 30 }, "count" : 1 }
{ "_id" : { "city" : "BJ", "age" : 20 }, "count" : 3 }
{ "_id" : { "city" : "SH", "age" : 20 }, "count" : 2 }

$bucket管道阶段只采用单个字段路径。您可以通过 "output" 选项拥有多个累加器,但 "groupBy" 是单个表达式。

请注意,您也可以使用 $let此处优先于单独的 $project管道阶段计算“年龄”。

N.B 如果你真的向 $bucket 抛出一些错误的表达式你会得到关于 $switch 的错误,这应该向您暗示这就是它在内部实现的方式。


如果您担心 $switch 中的编码然后生成它:

var ranges = [0,20,30,40,50,200];
var branches = [];
for ( var i=1; i < ranges.length; i++) {
  branches.push({ "case": { "$lt": [ "$$age", ranges[i] ] }, "then": ranges[i-1] });
}

db.user.aggregate([
  { "$group": {
    "_id": {
      "city": "$city",
      "age": {
        "$let": {
          "vars": {
            "age": { 
              "$subtract": [{ "$year": new Date() },{ "$year": "$birthDay" }]
            }
          },
          "in": {
            "$switch": { "branches": branches }
          }
        }
      }
    },
    "count": { "$sum": 1 }
  }}
])

关于mongodb - 如何实现 $bucket 按多个字段分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44481283/

相关文章:

mongodb - 如何在聚合中匹配和分组具有最大值的数组元素

聚合查询中的 Mongodb 限制数组

MongoDB - 无法获得覆盖查询

mongodb - 命令失败,错误 16020 (Location16020) : 'Expression $eq takes exactly 2 arguments. 1 were passed in.' on server localhost:27017

MongoDB:计算作为列表嵌入文档中的所有特定文档字段的平均值

node.js - Mongoose 聚合 : ObjectId from variable $in array not returning true

mongodb - 具有最大 y 的 mongo 聚合字段 x

javascript - 将一个文件中的 mongoose 现有模式模型重用到另一个文件中的模式模型

mongodb - 频率表生成 - MongoDB

node.js - 在 mongoose/mongodb/node 中使用异步回调循环