Javascript 如何在MongoDB MapReduce中生成累积结果
我刚刚开始在mongo中使用MapReduce,并使用一个复合键(date,candidate)进行查询,该键返回一个与该键关联的值(该候选人当天的投票总数)。我真正想要的是每个日期的累积投票数。也就是说,对于每个日期/候选人关键字,该值是在该日期当天和之前为该候选人投票的所有选票的总和 这是我目前的代码: 输入示例:Javascript 如何在MongoDB MapReduce中生成累积结果,javascript,mongodb,mapreduce,Javascript,Mongodb,Mapreduce,我刚刚开始在mongo中使用MapReduce,并使用一个复合键(date,candidate)进行查询,该键返回一个与该键关联的值(该候选人当天的投票总数)。我真正想要的是每个日期的累积投票数。也就是说,对于每个日期/候选人关键字,该值是在该日期当天和之前为该候选人投票的所有选票的总和 这是我目前的代码: 输入示例: { "interaction" : { "type" : "draft", "parameters" : { "v
{
"interaction" : {
"type" : "draft",
"parameters" : {
"value" : [
{
"candidate" : 453510,
"votes" : 2
},
{
"candidate" : 325786,
"votes" : 2
}
]
}
},
"created_at" : 1360796255
}
var mapFn = function() {
var right = function(str, n) {
return str.substring(str.length, str.length - n);
}
var toDate = function(epochTimeSec) {
var d = new Date(1000 * epochTimeSec);
var yr = d.getYear() + 1900;
var mn = d.getMonth() + 1;
var dt = d.getDate();
return '' + right('0000' + yr, 4) + '-' + right('00' + mn, 2) + '-' + right('00' + dt, 2);
}
for(var i=0; i<this.interaction.parameters.value.length; i++)
{
vote = this.interaction.parameters.value[i];
var creationDate = toDate(this.created_at);
var votedCandidate = vote.candidate;
emit( {date: creationDate, candidate: votedCandidate}, { quantity: candidate.quantity } );
}
}
var reduceFn = function(key, values) {
var sum = 0;
values.forEach(function(doc) {
sum += doc.quantity;
});
return { quantity: sum };
}
db.collection_mr.drop();
db.collection.mapReduce(mapFn, reduceFn, { out: 'collection_mr' } );
function printData(r) {
print(r._id.date + ", " + r._id.candidate + ", " + r.value.quantity);
}
db.collection_mr.find().forEach(printData);
地图:
{
"interaction" : {
"type" : "draft",
"parameters" : {
"value" : [
{
"candidate" : 453510,
"votes" : 2
},
{
"candidate" : 325786,
"votes" : 2
}
]
}
},
"created_at" : 1360796255
}
var mapFn = function() {
var right = function(str, n) {
return str.substring(str.length, str.length - n);
}
var toDate = function(epochTimeSec) {
var d = new Date(1000 * epochTimeSec);
var yr = d.getYear() + 1900;
var mn = d.getMonth() + 1;
var dt = d.getDate();
return '' + right('0000' + yr, 4) + '-' + right('00' + mn, 2) + '-' + right('00' + dt, 2);
}
for(var i=0; i<this.interaction.parameters.value.length; i++)
{
vote = this.interaction.parameters.value[i];
var creationDate = toDate(this.created_at);
var votedCandidate = vote.candidate;
emit( {date: creationDate, candidate: votedCandidate}, { quantity: candidate.quantity } );
}
}
var reduceFn = function(key, values) {
var sum = 0;
values.forEach(function(doc) {
sum += doc.quantity;
});
return { quantity: sum };
}
db.collection_mr.drop();
db.collection.mapReduce(mapFn, reduceFn, { out: 'collection_mr' } );
function printData(r) {
print(r._id.date + ", " + r._id.candidate + ", " + r.value.quantity);
}
db.collection_mr.find().forEach(printData);
输出:
{
"interaction" : {
"type" : "draft",
"parameters" : {
"value" : [
{
"candidate" : 453510,
"votes" : 2
},
{
"candidate" : 325786,
"votes" : 2
}
]
}
},
"created_at" : 1360796255
}
var mapFn = function() {
var right = function(str, n) {
return str.substring(str.length, str.length - n);
}
var toDate = function(epochTimeSec) {
var d = new Date(1000 * epochTimeSec);
var yr = d.getYear() + 1900;
var mn = d.getMonth() + 1;
var dt = d.getDate();
return '' + right('0000' + yr, 4) + '-' + right('00' + mn, 2) + '-' + right('00' + dt, 2);
}
for(var i=0; i<this.interaction.parameters.value.length; i++)
{
vote = this.interaction.parameters.value[i];
var creationDate = toDate(this.created_at);
var votedCandidate = vote.candidate;
emit( {date: creationDate, candidate: votedCandidate}, { quantity: candidate.quantity } );
}
}
var reduceFn = function(key, values) {
var sum = 0;
values.forEach(function(doc) {
sum += doc.quantity;
});
return { quantity: sum };
}
db.collection_mr.drop();
db.collection.mapReduce(mapFn, reduceFn, { out: 'collection_mr' } );
function printData(r) {
print(r._id.date + ", " + r._id.candidate + ", " + r.value.quantity);
}
db.collection_mr.find().forEach(printData);
谢谢你的帮助
编辑
作为对评论的回应,我加入了一个示例输入。澄清-上述代码正确返回每个日期的所有投票总数。不过,我想对其进行修改,使之在每个日期返回该日期或该日期之前的所有投票总数
为了回答Asya Kamsky的问题,这将在临时基础上手动运行,因此需要在输入日期(可能不是当前日期)之前输出所有数据。使用聚合框架而不是mapReduce可以更轻松地解决问题。摘自: MongoDB聚合框架提供了一种计算 聚合值而不必使用map reduce。而map-reduce 是强大的,它往往是比许多简单的必要困难 聚合任务,例如合计或平均字段值 此聚合命令返回预期结果:
// target date as unix timestamp, example: 2013-02-28T23:59:59)
targetDate = Date.UTC(2013,1,28,23,59,59)/1000; // month -1 !!
db.xx.aggregate([
// select documents created_at up to target date
// note: this match uses an index, if defined on created_at
{ $match: {
"created_at": { $lte: targetDate }
}},
// unwind the "value" array
{ $unwind: "$interaction.parameters.value" },
// group by candidates, sum up votes
{ $group: {
_id: "$interaction.parameters.value.candidate",
votes: { $sum: "$interaction.parameters.value.votes" }
}},
])
结果:
{
"result" : [
{
"_id" : 325786,
"votes" : 2
},
{
"_id" : 453510,
"votes" : 2
}
],
"ok" : 1
}
究竟什么是不起作用的?你能提供一份收集的样本文档吗?就收集累积结果而言,您计划多久运行一次MR作业?每天都想得到前一天的选票或类似的东西?谢谢你的评论。我已经在上面加入了一个输入示例,并重申了我的问题。