0

I tried to use twice MapReduce aggregation to get unique user number per month.

The first MR function work out a mr_buyer_payment collection, like this:

{ "_id" : { "u" : "01329f19-27b0-435b-9ca1-450984024a31", "tid" : ISODate("2013-09-01T00:00:00Z") }, "value" : { "payment" : 38, "count_pay" : 1 } }
{ "_id" : { "u" : "264dd104-b934-490b-988e-5822fd7970f6", "tid" : ISODate("2013-09-01T00:00:00Z") }, "value" : { "payment" : 4.99, "count_pay" : 1 } }
{ "_id" : { "u" : "27bb8f72-a13e-4676-862c-02f41fea1bc0", "tid" : ISODate("2013-09-01T00:00:00Z") }, "value" : { "payment" : 11.98, "count_pay" : 2 } }

The second MR function works well with small data set , but when query grows more than 100 records, it gets wrong result , some value is NaN.

The debug log shows some value in Reduce function like v.payment, v.count_user became undefine.

date:Sun Jun 30 2013 17:00:00 GMT-0700 (PDT)  value:undefined / 162 / undefined

And the MR result info is wired:

{
    "result" : "mr_buyer_all",
    "timeMillis" : 29,
    "counts" : {
        "input" : 167,
        "emit" : 167,
        "reduce" : 6,  // it should be 3, as same as "output" number
        "output" : 3
    },
    "ok" : 1,
}

This is 2nd MR function:

db.mr_buyer_payment.mapReduce(
    function(){
        var key = this._id.tid;
        var value = {
            payment:this.value.payment,
            count_pay:this.value.count_pay,
            count_user:1
        };
        if (value.count_pay>0)
        {
            print("date:"+key+"  u:"+this._id.u+"value:"+value.payment+" / "+value.count_pay+" / "+value.count_user);
            emit(key,value);
        }
    },
    function(key,values){
        var result = {revenue:0,count_pay:0,user:0};
        values.forEach(function(v){
            if (!v.count_user)
            {
                print("date:"+key+"  "+"value:"+v.payment+" / "+v.count_pay+" / "+v.count_user);
            } else
            {
                result.revenue += v.payment;
                result.count_pay += v.count_pay;
                result.user += v.count_user;
            }

        });
        return result;
    },
    {
        out:{replace:"mr_buyer_all"}
    }
)

1 Answer 1

2

The sub-document in Reduce function should use same format as one in Map function. So the solution is :

function(key,values){
    // the following key must be as same as the object in map
    var r = {payment:0,count_pay:0,count_user:0}
    values.forEach(function(v){
        r.payment += v.payment;
        r.count_pay += v.count_pay;
        r.count_user += v.count_user;
    });
    return r;
},
Sign up to request clarification or add additional context in comments.

Comments

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.