-3

我有一个名为configurations. 在configurations集合中有许多公司。每个公司都有workstations, servers, printers, phones.

架构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
4

1 回答 1

3

使用聚合框架在管道步骤中利用$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>


- 更新 -

从评论跟踪来看,您使用 Promise 提出的解决方案不起作用,因为您没有使用管道返回 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
        })
    });
})
于 2016-08-16T15:56:29.273 回答