6

I have a map reduce function that works on a collection as follows:

function Map() {
    emit (
        this.name, 
        { 
            count : 1,
            flag : this.flag

        }
    );
}
function Reduce(key, values) {
    var count = 0;
    var flag = false;

    for (var i in values){
        count = count + 1;
        if (i.flag)
             flag = true;
    }

    var reduced = {
        count : count,
        flag  : flag
    }
    return reduced;
}
function Finalize(key, reduced) {

    if (reduced.count>10 || reduced.flag){
        var finalized = {
            "count" : reduced.count 
        }
        return reduced;
    }

    return null;
}

What I am trying to do is that the Finalize will only return objects that pass a certain threshold (e.g. count>10). Currently it is still returning objects and the count is just null.

Any ideas?

checklist
  • 12,340
  • 15
  • 58
  • 102

2 Answers2

3

I would suggest you use the aggregation framework instead as it's much faster and easier to understand. Your above M/R/F can be written as easily as:

db.so.insert( { name: "Derick" } );
db.so.insert( { name: "Derick" } );
db.so.insert( { name: "Derick" } );
db.so.insert( { name: "Derick" } );
db.so.insert( { name: "Checklist" } );
db.so.insert( { name: "Checklist" } );
db.so.insert( { name: "Whoop" } );
db.so.insert( { name: "Whoop", flagged: true } );
db.so.aggregate( [
    { $group: { 
        _id: '$name', 
        count: { $sum: 1 }, 
        flagged: { $sum: 
            { $cond: [ { $eq: [ '$flagged', true ] }, 1, 0 ] } 
        } 
    } },
    { $match: { $or: [ { count: { $gt: 3 } }, { flagged: { $gt: 0 } } ] } }
] );

Which returns:

{
    "result" : [
        {
            "_id" : "Whoop",
            "count" : 2,
            "flagged" : 1
        },
        {
            "_id" : "Derick",
            "count" : 4,
            "flagged" : 0
        }
    ],
    "ok" : 1
}
Derick
  • 35,169
  • 5
  • 76
  • 99
  • Thanks Derick. I can't use the aggregation as there is some more logic to the map/reduce which I didn't put in for simplification of the question. – checklist Aug 05 '13 at 17:44
  • Please provide that in the question... A/F is more powerful than you think! – Derick Aug 05 '13 at 21:42
  • I have added a more complex example where the count should be more than 3 OR one of the items is flagged – checklist Aug 06 '13 at 07:41
  • Just fixed that in the match for you... $match is just a query. – Derick Aug 06 '13 at 09:23
  • This doesn't solve the mapReduce finalize filter question that is required for complex ops, or at leats more complex than aggregate can handle. – jmdiego Jan 17 '17 at 18:55
2

You can't.
Finalize will can only change the format of your value, but you cannot cancel out the key (which is actually dictated by the map phase emits).

igorludi
  • 1,519
  • 2
  • 18
  • 31