1

Hi I have a document that has the following structure, I want to sum of $ of all different fruits in all cities so output wud be { fruits : { apples : $9, grapes : $15, pears : $14 , oranges : $20 } }

db.fruitmarket

{ _id : 1 marketname : LA, fruit : { apples : $2, grapes : $3 , pears : $4, oranges : $5}

_id : 1 marketname : CHI, fruit : { apples : $3, grapes : $5 , pears : $4, oranges : $7}

_id : 1 marketname : NY, fruit : { apples : $4, grapes : $7 , pears : $6, oranges : $8}

}

krish727
  • 303
  • 1
  • 3
  • 11

1 Answers1

1

UPDATED ANSWER

First, to make sure I could test this, I created a collection with the fruit information in it and inserted your example data:

db.fruitmarket.insert(
   [
       { marketname : "LA", fruit : { apples : 2, grapes : 3 , pears : 4, oranges : 5} },
       { marketname : "CHI", fruit : { apples : 3, grapes : 5 , pears : 4, oranges : 7} },
       { marketname : "NY", fruit : { apples : 4, grapes : 7 , pears : 6, oranges : 8} }
   ]
)

map function that emits all the properties of the fruit key for each document:

function() {
    for (var key in this.fruit) {
        emit(key, this.fruit[key]);
    }
}

reduce function that sums up all of the fruit values:

function(key, values) {
    return Array.sum(values);
}

Finally, I ran the map-reduce:

db.loadServerScripts();
db.fruitmarket.mapReduce(mapSubProperties, reduceSubProperties, { out: "fruits"})

And I got the result you were looking for:

/* 0 */
{
    "_id" : "apples",
    "value" : 9
}

/* 1 */
{
    "_id" : "grapes",
    "value" : 15
}

/* 2 */
{
    "_id" : "oranges",
    "value" : 20
}

/* 3 */
{
    "_id" : "pears",
    "value" : 14
}
  • If I dont know the key value before hand, how do I handle the aggregation. can I write something more generic where all the "fruits" not known before hand. – krish727 Nov 07 '14 at 22:36
  • I tried to look at ways to do that, but it looks like that might only be possible if the fruits object stores an array of values. If all of that were in an array, you could use Map-Reduce or an $unwind aggregation to do exactly what you're attempting to do. Alternatively, you may try using a for loop on the properties of fruits, but i am not sure – Kusha Tavakoli Nov 07 '14 at 22:47
  • So I am not sure I totally understand the solution presented in this question/answer - http://stackoverflow.com/questions/2997004/using-map-reduce-for-mapping-the-properties-in-a-collection - but I think this gets a lot closer to answering your question. In addition, your solution might actually look simpler because you don't have to worry about recursion in your case - you already know all of your fruits are in your "fruit" key, right? – Kusha Tavakoli Nov 08 '14 at 00:59
  • @krish727 - check out the updated answer. This answer is vastly superior to my initial response as it goes through everything in the "fruits" subdocument, and then returns the total dollar value for each type of fruit. – Kusha Tavakoli Nov 08 '14 at 01:27