Đối với biểu mẫu thực tế của bạn và do đó giả sử rằng bạn thực sự biết các giá trị có thể có cho "loại" thì bạn có thể thực hiện việc này với hai $ nhóm
các giai đoạn và một số sử dụng $ cond
nhà điều hành:
db.types.aggregate([
{ "$group": {
"_id": {
"stat": "$stat",
"type": "$type"
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.stat",
"type1": { "$sum": { "$cond": [
{ "$eq": [ "$_id.type", 1 ] },
"$count",
0
]}},
"type2": { "$sum": { "$cond": [
{ "$eq": [ "$_id.type", 2 ] },
"$count",
0
]}},
"type3": { "$sum": { "$cond": [
{ "$eq": [ "$_id.type", 3 ] },
"$count",
0
]}}
}}
])
Điều nào cho chính xác:
{ "_id" : "foobar", "type1" : 2, "type2" : 1, "type3" : 1 }
Tôi thực sự thích biểu mẫu động hơn với hai $ nhóm
giai đoạn mặc dù:
db.types.aggregate([
{ "$group": {
"_id": {
"stat": "$stat",
"type": "$type"
},
"count": { "$sum": 1 }
}},
{ "$group": {
"_id": "$_id.stat",
"types": { "$push": {
"type": "$_id.type",
"count": "$count"
}}
}}
])
Không giống đầu ra nhưng có chức năng và linh hoạt với các giá trị:
{
"_id" : "foobar",
"types" : [
{
"type" : 3,
"count" : 1
},
{
"type" : 2,
"count" : 1
},
{
"type" : 1,
"count" : 2
}
]
}
Ngược lại, nếu bạn cần cùng một định dạng đầu ra nhưng cần các trường linh hoạt thì bạn luôn có thể sử dụng mapReduce, nhưng nó không chính xác cùng một đầu ra.
db.types.mapReduce(
function () {
var obj = { };
var key = "type" + this.type;
obj[key] = 1;
emit( this.stat, obj );
},
function (key,values) {
var obj = {};
values.forEach(function(value) {
for ( var k in value ) {
if ( !obj.hasOwnProperty(k) )
obj[k] = 0;
obj[k]++;
}
});
return obj;
},
{ "out": { "inline": 1 } }
)
Và theo kiểu mapReduce điển hình:
"results" : [
{
"_id" : "foobar",
"value" : {
"type1" : 2,
"type2" : 1,
"type3" : 1
}
}
],
Nhưng đó là những lựa chọn của bạn