mapReduce不调用map也不减少

时间:2014-06-02 17:53:50

标签: node.js mongodb map mapreduce aggregation-framework

我刚开始使用mongodb,我在使用mapReduce函数时遇到了麻烦。 由于某种原因,似乎没有调用地图和减少功能。

这是我的代码:

@getMonthlyReports: (req, res) ->
    app_id = req.app.id
    start = moment().subtract('years', 1).startOf('month').unix()
    end = moment().endOf('day').unix()
    console.log(start)
    console.log(end)

    map = ->
        geotriggers = 0
        pushes = 0
        console.log("ok")
        date = moment(@timestamp).startOf('month').unix()
        for campaign in @campaigns
            if campaign.geotriggers?
                geotriggers += campaign.geotriggers
            else if campaign.pushes?
                pushes += campaign.pushes

        emit date,
            geotriggers: geotriggers
            pushes: pushes

    reduce = (key, values) ->
        console.log("ok")
        geotriggers = 0
        pushes = 0
        for value in values
            geotriggers += value.geotriggers
            pushes += value.pushes
        geotriggers: geotriggers
        pushes: pushes


    common.db.collection(req.app.id + "_daily_campaign_reports").mapReduce map, reduce,
        query:
            timestamp:
                $gte: start
                $lt: end

        out:
            inline: 1
    , (err, results) ->
        console.log(results)


        ResponseHelper.returnMessage req, res, 200, results

我放了一些console.logs,似乎没有调用map和reduce函数。 我的结果也是未定义的。

我有什么遗失的吗?

1 个答案:

答案 0 :(得分:1)

除了我已经评论过你的mapReduce失败的原因是由于调用了服务器上不存在的库函数(moment.js),这对mapReduce来说并不是很好用。

虽然mapReduce有它的用途,但像这样的简单聚合情况更适合于aggregation framework,因为它是本机C ++实现,而不是在JavaScript解释器中运行的mapReduce。因此处理速度更快。

您需要的是startend的现有unix时间戳值以及当月的当前日期dayOfMonth),以便进行日期数学运算:

db.collection.aggregate([
    // Match documents using your existing start and end values
    { "$match": {
        "timestamp": { "$gte": start, "$lt": end }
    }},

    // Unwind campaigns array
    { "$unwind": "$campaigns" },

    // Group on the start of month value
    { "$group": {
        "_id": { 
            "$subtract": [
               "$timestamp",
               { "$mod": [ "$timestamp", 1000 * 60 * 60 * 24 * dayOfMonth ] }
            ]
        },
        "geotriggers": { 
            "$sum": {
                "$cond": [
                   "$campaigns.geotriggers",
                   1,
                   0
                ]
            }
        },
        "pushes": { 
            "$sum": {
                "$cond": [
                   "$campaigns.pushes",
                   1,
                   0
                ]
            }
        },
    }}
])

如果我正确地阅读了您的代码,那么每个文档都包含一个用于" campaign"的数组,因此要在聚合框架中处理这个问题,您可以使用$unwind管道阶段来展示每个数组成员作为自己的文档。

通过更改"时间戳"在_id键的$group阶段完成日期数学运算。 value等于月份的起始日期,这与您的代码尝试的内容相同。有争议的是你可以在这里使用null因为你的范围选择只会产生一个单一的日期值,但这只是为了表明日期数学是可能的。

"解开"数组元素,我们处理每个元素就像" for循环"有条件地添加" geotriggers"和"推动"使用$cond运算符。再次假设您的代码将这些字段评估为布尔值true / false,这是$cond的评估部分

您的查询条件当然只是在管道开头的$match阶段使用相同的范围查询。

这基本上做同样的事情而不依赖于服务器端处理中的其他库,并且它也更快。

请参阅其他Aggregation Framework运算符以供参考。