我刚开始使用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函数。 我的结果也是未定义的。
我有什么遗失的吗?
答案 0 :(得分:1)
除了我已经评论过你的mapReduce失败的原因是由于调用了服务器上不存在的库函数(moment.js),这对mapReduce来说并不是很好用。
虽然mapReduce有它的用途,但像这样的简单聚合情况更适合于aggregation framework,因为它是本机C ++实现,而不是在JavaScript解释器中运行的mapReduce。因此处理速度更快。
您需要的是start
和end
的现有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运算符以供参考。