简体   繁体   中英

get undefined value in mongodb MapReduce

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"}
    }
)

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;
},

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM