将mapreduce查询转换为mongodb中的聚合

时间:2014-04-29 08:50:35

标签: java mongodb mapreduce aggregation-framework

以下是mapreduce查询:

mapper=function () {
    if (this.meta != null && this.meta.active == true && this.data != null && this.data.attributes != null && this.data.attributes.lang == "en" && this.data.attributes.geo == "us" && this.meta.client.id == "1") {
        if (this.meta.created > ISODate("2014-03-30 12:27:50")) {
            emit("querisAddedSinceLastWeek", {
                "count": 1
            });
        }
        if (this.data.expectedResults == null && this.data.attributes.lang == "en" && this.data.attributes.geo == "us" && this.meta.client.id == "1") {
            emit("queriesWithExpectedResultsCount", {
                "count": 1
            });
        }
        if (this.data.attributes.lang == "en" && this.data.attributes.geo == "us" && this.meta.client.id == "1" && this.meta.active == true) {
            emit("totalActiveQueriesCount", {
                "count": 1
            });
        }
    }
}

reducer=function (k, v) {
    counter = 0;
    for (i = 0; i < v.length; i++) {
        counter += v[i].count;
    }
    return {
        "count": counter
    }
}

db['ARTDocument.dev'].mapReduce(mapper,reducer,{out:{inline:1}});

在此查询中,某些条件对于所有3个查询都是通用的,并且每个查询只有一个条件。如果可能,我希望使用monodb中的聚合框架在单个查询中触发这些查询。 我希望在mongodb中的聚合框架中编写这个确切的查询。

我试过这个,但它不起作用。

db['ARTDocument.dev'].aggregate(

    {
        $match: {
            "meta.active": true,
            "meta.client.id": 1,
            "data.attributes.lang": "en",
            "data.attributes.geo": "us"
        }
    }, {
        $group: {
            _id: {
                $cond: [{
                        $lt: ["meta.created", ISODate("2014-03-30 12:27:50")]
                    },
                    "querisAddedSinceLastWeek",
                    "null"
                ]
            },
            count: {
                $sum: 1
            }
        }
    }, {
        $group: {
            _id: {
                $ifNull: ["data.expectedResults", "queriesWithoutExpectedResultsCount"]
            },
            count: {
                $sum: 1
            }
        }
    }

)

1 个答案:

答案 0 :(得分:0)

您对流程有一个正确的总体思路,但您的结构略有偏差。

你的第一阶段,$匹配有资格被计算的条件是好的。

match = {$match: {
         "meta.active": true,
         "meta.client.id": 1,
         "data.attributes.lang": "en",
         "data.attributes.geo": "us"
        }

你的下一个阶段是$ group,因为它应该是,但是你并没有对正确的密钥进行分组。由于您希望获得所有合格文档的总计,因此您应该将_id作为常量进行分组,并根据条件评估是否为真来执行$sum 1或0。

group = {$group: {
         _id: null,
         querisAddedSinceLastWeek : { $sum : {$cond: [
                    { $gt : [ meta.created, ISODate("2014-03-30 12:27:50") ] },
                    1, 0 ] }
         },
         queriesWithExpectedResultsCount: { $sum:
                    { $eq : [ data.expectedResults, null ] }, 
                    1, 0 ] }
         },
         totalActiveQueriesCount: { $sum : 1 }
} }

你的地图功能有一个很多的不必要(冗余)条件,通常更好地表达你真正想要的东西 - 但它目前正在做的是总结所有活动查询,并且还获得自上周以来的查询总和,以及具有null data.expectedResults的查询。

完全聚合,定义了以上两个阶段:

db['ARTDocument.dev'].aggregate( match, group );