在 MongoDB 中进行聚合分组

Grouping With aggregation in MongoDB

目前我在 MongoDB 中使用聚合。在我的 collections 中有一个带有省份和宗教的字段。我正在做这个

const data = await submit.aggregate([
    { "$group": { _id: { province: "$province" ,religion:"$religion"}, count: { $sum: 1 } } },
  ])

我的输出看起来像这样:

[
  { _id: { religion: 'a', province: 'aa' }, count: 1 },
  { _id: { religion: b, province: 'bb' }, count: 2 },
  { _id: { religion: 'c', province: 'bb'}, count: 2 },
  { _id: { religion: 'd', province: 'cc' }, count: 1 } 
]

预期输出:

[
  { _id: { religion: 'a ' }, count: 1 },
  { _id: { religion: 'a' }, count: 1 },
  { _id: { religion: null }, count: 6 },
  { _id: { religion: 'c' }, count: 1 },
  { _id: { religion: 'd' }, count: 2 },
  { _id: { religion: 'e' }, count: 6 },
  { _id: { religion: 'f' }, count: 15 },
  { _id: { religion: 'g' }, count: 2 },
 
 
] [
  { _id: { province: 'aa' }, count: 19 },
  { _id: { province: 'bb' }, count: 2 },
  { _id: { province: 'cc' }, count: 21 },
  
]

您同时寻找 2 个不同的 $group -- 这正是 $facet 的用途。将 $facet 想象成“multi-group”。给定类似于以下的输入集:

    { religion: 'a', province: 'aa' },
    { religion: 'b', province: 'aa' },
    { religion: 'c', province: 'aa' },
    { religion: 'c', province: 'bb' },
    { religion: 'd', province: 'bb' },
    { religion: 'e', province: 'cc' },      
    { religion: 'f', province: 'aa' },
    { religion: 'f', province: 'aa' },
    { religion: 'f', province: 'aa' },
    { religion: 'f', province: 'cc' }

然后这个管道:

db.foo.aggregate([
    {$facet: {
        "by_religion": [
            {$group: {_id: '$religion', N:{$sum:1}}}
        ],
        "by_province": [
            {$group: {_id: '$province', N:{$sum:1}}}
        ],
    }}  
]);

产生这个输出:

{
    "by_religion" : [
        {
            "_id" : "b",
            "N" : 1
        },
        {
            "_id" : "e",
            "N" : 1
        },
        {
            "_id" : "d",
            "N" : 1
        },
        {
            "_id" : "a",
            "N" : 1
        },
        {
            "_id" : "f",
            "N" : 4
        },
        {
            "_id" : "c",
            "N" : 2
        }
    ],
    "by_province" : [
        {
            "_id" : "bb",
            "N" : 2
        },
        {
            "_id" : "cc",
            "N" : 2
        },
        {
            "_id" : "aa",
            "N" : 6
        }
    ]
}

OP 试图通过做一些 data-as-LVAL 处理来进一步优化输出,虽然这通常被认为是一种糟糕的设计实践,但它有某些有用的应用程序。在$facet之后添加这个阶段:

    ,{$project: {
        // Reading this from insider-out:                                             
        // We use $map to turn the array of objects:                                  
        //   [ {_id:'d',N:1},{_id:'f',N:4}, ... ]                                     
        // into an array of K-v pairs (array of array):                               
        //   [ ['d',1] , ['f',4] , ...  ]                                             
        // That sets us up for $arrayToObject which will take                         
        // that array of arrays and turn it into an object:                           
        //   {'d':1, 'f':4, ... } 
        // The target field name is the same as the input so
        // we are simply overwriting the field.        
        "by_religion": {$arrayToObject: {$map: {
            input: '$by_religion',
                in: [ '$$this._id', '$$this.N' ]
            }}
        },
        "by_province": {$arrayToObject: {$map: {
            input: '$by_province',
                in: [ '$$this._id', '$$this.N' ]
            }}
        }
    }}

产生:

{
    "by_religion" : {
        "d" : 1,
        "b" : 1,
        "c" : 2,
        "f" : 4,
        "a" : 1,
        "e" : 1
    },
    "by_province" : {
        "bb" : 2,
        "cc" : 2,
        "aa" : 6
    }
}

lval/rval 后处理的一个变体使用这个 $project 而不是上面的那个:

    ,{$project: {
          "by_religion": {$map: {
              input: '$by_religion',
              in: {$arrayToObject: [ [{k:'$$this._id',v:'$$this.N'}] ]}
          }},
          "by_province": {$map: {
              input: '$by_province',
              in: {$arrayToObject: [ [{k:'$$this._id',v:'$$this.N'}] ]}
          }},
    }}

产生一个数组:

{
    "by_religion" : [
        {"b" : 1},
        {"c" : 2},
        {"a" : 1},
        {"f" : 4},
        {"d" : 1},
        {"e" : 1}
    ],
    "by_province" : [
        {"cc" : 2},
        {"aa" : 6},
        {"bb" : 2}
    ]
}