3

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).

2
  • can you tell about the collection? Commented Apr 24, 2015 at 7:07
  • 1
    may be you should use three separate aggregation to find out brand, price and family, other wise use map reduce Commented Apr 24, 2015 at 8:07

1 Answer 1

1

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 }
});
Sign up to request clarification or add additional context in comments.

1 Comment

This does indeed work but as you stated, there is probably no nice way of getting the keys form an object. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.