我有一个名为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
答案 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
})
});
})