Mongodb Count对象属性

时间:2016-08-16 15:44:00

标签: mongodb count mongodb-query aggregation-framework mongodb-aggregation

我有一个名为configurations的集合。在configurations集合中有很多公司。每家公司都有workstationsserversprintersphones

configurations的架构是

Configuration: {
    CompanyName: String
    Type: String /// server, phones etc
}

我想要那样的输出

Company : ABC 
Servers : 5
Phones 6
Workstations: 0

Company: XYZ 
Workstations: 9
Servers: 7
Phones: 5

1 个答案:

答案 0 :(得分:2)

使用聚合框架利用$cond管道步骤中的$group运算符,根据Type字段值评估计数,如下所示:

db.configurations.aggregate([    
    { 
        "$group": { 
            "_id": "$CompanyName",             
            "server_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$Type", "server" ] }, 1, 0 ]
                }
            },
            "phone_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$Type", "phone" ] }, 1, 0 ]
                }
            },
            "workstation_count": {
                "$sum": {
                    "$cond": [ { "$eq": [ "$Type", "workstation" ] }, 1, 0 ]
                }
            }
        }  
    },
    {
        "$project": {
            "_id": 0, "Company": "$_id",            
            "Workstations": "$workstation_count",
            "Servers": "$server_count",
            "Phones": "$phone_count",
         }
    }        
])

如果您事先不知道Type值并想要动态创建管道数组,请在该字段上运行 distinct 命令。这将为您提供一个包含不同类型列表的对象:

var result = db.runCommand ( { distinct: "configurations", key: "Type" } )
var types = result.values;
printjson(types); // this will print ["server", "phone", "workstation"] etc

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

var groupObj = { "$group": { "_id": "$CompanyName" } },
    projectObj = { "$project": { "_id": 0 } };

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

var projectPipeline = types.reduce(function(obj, type) { // set the project pipeline object 
    obj["$project"][type+'s'] = "$" + type + "_count";
    return obj;
}, projectObj );

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

db.configurations.aggregate([groupPipeline, projectPipeline]);

查看下面的演示。

var types = ["server", "workstation", "phone"],
	groupObj = { "$group": { "_id": "$CompanyName" } },
	projectObj = { "$project": { "_id": 0 } };

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

var projectPipeline = types.reduce(function(obj, type) { // set the project pipeline object 
	obj["$project"][type+"s"] = "$" + type + "_count";
	return obj;
}, projectObj );

var pipeline = [groupPipeline, projectPipeline]

pre.innerHTML = JSON.stringify(pipeline, null, 4);
<pre id="pre"></pre>

- 更新 -

从评论跟踪中,您建议使用promises的解决方案无效,因为您没有使用管道返回promise。

重构您的代码以遵循此模式:

Ticket.distinct("status.name").then(function(result) { 
    var groupPipeline, groupObj, projectObj, projectPipeline;
    groupObj = {
            "$group": {
                "_id": "$company.name" /// company is object
                // name is attribute of company
            }
        },
        projectObj = {
            "$project": {
                "_id": 0
            }
        };

    groupPipeline = result.reduce(function(obj, result) { 
        obj["$group"][result + "_count"] = {
            "$sum": {
                "$cond": [{
                    "$eq": ["$Type", result]
                }, 1, 0]
            }
        };
        return obj;
    }, groupObj);

    projectPipeline = result.reduce(function(obj, result) { 
        obj["$project"][result + 's'] = "$" + result + "_count";
        return obj;
    }, projectObj);

    return [groupPipeline, projectPipeline];

}).then(function(pipeline) {
    return Ticket.aggregate(pipeline).then(function(results) {
        console.log(results);
        return res.json({
            status: true,
            code: 200,
            data: results
        })
    });
})