MongoDB组并以id作为键

Xer*_*oid 6 mongodb mongodb-query aggregation-framework

是否有可能将聚合函数的结果作为key:count

例:

我有以下聚合查询:

db.users.aggregate([
  {
    $group: {
      _id: "$role",
      count: {
        $sum: 1
      }
    }
  }
])
Run Code Online (Sandbox Code Playgroud)

结果如下:

{ "_id" : "moderator", "count" : 469 }
{ "_id" : "superadmin", "count" : 1 }
{ "_id" : "user", "count" : 2238 }
{ "_id" : "admin", "count" : 11 }
Run Code Online (Sandbox Code Playgroud)

所以这一切都很好,但有没有一种方法(可能使用$project)使结果看起来像这样(即使用role键作为键和count值):

{ "moderator": 469 }
{ "superadmin": 1 }
{ "user": 2238 }
{ "admin": 11 }
Run Code Online (Sandbox Code Playgroud)

我可以通过使用JS对结果进行后处理来做到这一点,但我的目标是直接通过聚合函数来完成.

chr*_*dam 8

使用 MongoDb 3.6 及更新版本,您可以利用$arrayToObject运算符和$replaceRoot管道的使用来获得所需的结果。您需要运行以下聚合管道:

db.users.aggregate([
    { 
        "$group": {
            "_id": { "$toLower": "$role" },
            "count": { "$sum": 1 }
        }
    },
    { 
        "$group": {
            "_id": null,
            "counts": {
                "$push": {
                    "k": "$_id",
                    "v": "$count"
                }
            }
        }
    },
    { 
        "$replaceRoot": {
            "newRoot": { "$arrayToObject": "$counts" }
        } 
    }    
])
Run Code Online (Sandbox Code Playgroud)

对于旧版本,管道步骤中的$cond运算符$group可以有效地用于根据角色字段值评估计数。您可以按如下方式构建整体聚合管道,以生成所需格式的结果:

db.users.aggregate([    
    { 
        "$group": { 
            "_id": null,             
            "moderator_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$role", "moderator" ] }, 1, 0 ]
                }
            },
            "superadmin_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$role", "superadmin" ] }, 1, 0 ]
                }
            },
            "user_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$role", "user" ] }, 1, 0 ]
                }
            },
            "admin_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$role", "admin" ] }, 1, 0 ]
                }
            } 
        }  
    },
    {
        "$project": {
            "_id": 0, 
            "moderator": "$moderator_count",
            "superadmin": "$superadmin_count",
            "user": "$user_count",
            "admin": "$admin_count"
        }
    }
])
Run Code Online (Sandbox Code Playgroud)

从注释跟踪中,如果您事先不知道角色并想动态创建管道数组,请distinct在角色字段上运行命令。这将为您提供一个包含不同角色列表的对象:

var result = db.runCommand ( { distinct: "users", key: "role" } )
var roles = result.values;
printjson(roles); // this will print ["moderator", "superadmin", "user",  "admin"]
Run Code Online (Sandbox Code Playgroud)

现在给出上面的列表,您可以通过创建一个对象来组装您的管道,该对象将使用 JavaScript 的reduce()方法设置其属性。下面证明了这一点:

var groupObj = { "_id": null },
    projectObj = { "_id": 0 }

var groupPipeline = roles.reduce(function(obj, role) { // set the group pipeline object 
    obj[role + "_count"] = {
        "$sum": {
            "$cond": [ { "$eq": [ "$role", role ] }, 1, 0 ]
        }
    };
    return obj;
}, groupObj );

var projectPipeline = roles.reduce(function(obj, role) { // set the project pipeline object 
    obj[role] = "$" + role + "_count";
    return obj;
}, projectObj );
Run Code Online (Sandbox Code Playgroud)

在最终聚合管道中使用这两个文档作为:

db.users.aggregate([groupPipeline, projectPipeline]);
Run Code Online (Sandbox Code Playgroud)

检查下面的演示。

db.users.aggregate([
    { 
        "$group": {
            "_id": { "$toLower": "$role" },
            "count": { "$sum": 1 }
        }
    },
    { 
        "$group": {
            "_id": null,
            "counts": {
                "$push": {
                    "k": "$_id",
                    "v": "$count"
                }
            }
        }
    },
    { 
        "$replaceRoot": {
            "newRoot": { "$arrayToObject": "$counts" }
        } 
    }    
])
Run Code Online (Sandbox Code Playgroud)
db.users.aggregate([    
    { 
        "$group": { 
            "_id": null,             
            "moderator_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$role", "moderator" ] }, 1, 0 ]
                }
            },
            "superadmin_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$role", "superadmin" ] }, 1, 0 ]
                }
            },
            "user_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$role", "user" ] }, 1, 0 ]
                }
            },
            "admin_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$role", "admin" ] }, 1, 0 ]
                }
            } 
        }  
    },
    {
        "$project": {
            "_id": 0, 
            "moderator": "$moderator_count",
            "superadmin": "$superadmin_count",
            "user": "$user_count",
            "admin": "$admin_count"
        }
    }
])
Run Code Online (Sandbox Code Playgroud)