使用聚合框架的问题是您不能为对象的属性指定任意键名。因此,如果不能指定所有可能的键名,就无法使用它进行重塑。
因此,要获得结果,您需要在 JavaScript 中工作,例如 mapReduce:
首先定义一个映射器:
var mapper = function () {
var key = this["class"];
delete this._id;
delete this["class"];
emit( key, this );
};
然后是减速器:
var reducer = function (key, values) {
var reducedObj = {};
values.forEach(function(value) {
if ( !reducedObj.hasOwnProperty(value.type) )
reducedObj[value.type] = [];
reducedObj[value.type].push( value.Name );
});
return reducedObj;
};
而且因为您有(至少在您的示例中)可能从映射器发出的项目只有 1 个键值,所以您还需要一个 finalize 函数:
var finalize = function (key,value) {
if ( value.hasOwnProperty("name") ) {
value[value.type] = value.name;
delete value.type;
delete value.name;
}
return value;
};
然后你调用mapReduce函数如下:
db.collection.mapReduce(
mapper,
reducer,
{ "out": { "inline": 1 }, "finalize": finalize }
)
这给出了以下输出:
"results" : [
{
"_id" : "class A",
"value" : {
"type 1" : [
"ObjectA1"
],
"type 2" : [
"ObjectA2_1",
"ObjectA2_2"
]
}
},
{
"_id" : "class B ",
"value" : {
"type" : "type 3",
"Name" : "ObjectB3"
}
}
],
虽然结果以非常 mapReduce 的方式格式化,但它肯定与您的结果大致相同。
但如果您真的想更进一步,您可以随时执行以下操作:
定义另一个映射器:
var mapper2 = function () {
emit( null, this );
};
还有一个减速器:
var reducer2 = function (key,values) {
reducedObj = {};
values.forEach(function(value) {
reducedObj[value._id] = value.value;
});
return reducedObj;
};
然后运行第一个 mapReduce 并将输出输出到一个新集合:
db.collection.mapReduce(
mapper,
reducer,
{ "out": { "replace": "newcollection" }, "finalize": finalize }
)
接着是新集合上的第二个 mapReduce:
db.newcollection.mapReduce(
mapper2,
reducer2,
{ "out": { "inline": 1 } }
)
这就是你的结果:
"results" : [
{
"_id" : null,
"value" : {
"class A" : {
"type 1" : [
"ObjectA1"
],
"type 2" : [
"ObjectA2_1",
"ObjectA2_2"
]
},
"class B " : {
"type" : "type 3",
"Name" : "ObjectB3"
}
}
}
],