Reputation: 4457
I am trying to use MongoDB's aggregate-framework to generate documents from a collection which has the following structure:
{
"_id" : ObjectId("5510eb56f877bbef153d236d"),
"attributes" : {
"brand" : "Mercedes",
"price" : 289,
"family" : "GARDEN"
},
"name" : "Bigger Fix Soft Crisps"
}
{
"_id" : ObjectId("5510eb56f877bbef153d236e"),
"attributes" : {
"brand" : "Adelholzener",
"price" : 683,
"family" : "COMPUTER"
},
"name" : "Soft Stockhome Chips"
}
{
"_id" : ObjectId("5510eb56f877bbef153d236f"),
"attributes" : {
"brand" : "Pepsi",
"price" : 789,
"family" : "CAR"
},
"name" : "Light Yearsailfresh Meat"
}
I want to to get the aggregation of all fields from the attributes
subdocument with their possible values. Since the fields in the subdocument are not known I cannot simply use the fields given in this example and therefore has to be dynamic. The result should look similar to this:
{
"_id" : "brand",
"values" : [
"Mercedes", "Adelholzener", "Pepsi"
]
},
{
"_id" : "price",
"values" : [
289, 683, 789
]
},
{
"_id" : "family",
"values" : [
"GARDEN", "COMPUTER", "CAR"
]
}
I haven't found a solution so far for this particularly problem. I tried with $project
and $unwind
(which does obviously only work for arrays).
Upvotes: 3
Views: 174
Reputation: 3772
Tried to figure out how to do it w aggregate but i'm not sure it's possible as you can't get the keys in an object in any nice way.
Here is a MapReduce job that does the thing:
db.runCommand({
"mapreduce" : "test_collection", // Change collection here
"map" : function() {
for (var key in this.attributes) {
// Emit objects w array as we cannot reduce arrays directly
emit(key, {x: [this.attributes[key]]});
}
},
"reduce" : function(key, values) {
var res = [];
values.forEach(function (d) {
Array.prototype.push.apply(res, d.x);
});
return {x: res};
},
"finalize": function (key, reducedVal) {
return reducedVal.x;
},
"out": { inline: 1 }
});
Upvotes: 1