以下方法使用的客户端展现代码(html)是一样的:
<h2>展会评分:<span class="label label-success">{{rankAverage}}</span></h2>
.
使用MapReduce
MapReduce一次性将所有展会的用户评分平均值计算出来,优点是每次用户请求页面时不需要计算,直接从计算结果中取值。 缺点是实时性差,由于MapReduce计算比较耗时,且计算结果存储在一个单独的collection中, 新的计算结果会覆盖旧的,所以不能一次只计算一个展会的平均值(因为计算结果collection会覆盖掉有来包含所有结果的collection), 只能在服务清闲的时间(比如凌晨)进行一次批量计算。
在MongoDB中运行mapReduce:
db.userComments.mapReduce(
function(){ emit(this.fairId, this.rank); },
function(key, values) { return Array.avg(values); },
{ out: "rank_avg" }
);
客户端控制器(js):
UserAvgRank = new Mongo.Collection("rank_avg");
Template.UserComments.helpers({
rankAverage: function() {
var rec = UserAvgRank.findOne({ _id: Router.current().params._id });
return Math.round(rec.value * 10) / 10;
}
});
aggregate计算平均值
使用MongoDB collection的aggregate方法在用户请求时实时计算平均值,优缺点与MapReduce方法正好相反。
在Meteor 1.0.3版本中,不支持collection的aggregate方法, 可以通过安装meteorhacks:aggregate包的方法解决这个问题,但这个方法也只能运行在服务端。
Template.UserComments.helpers({
rankAverage: function() {
var rec = Comments.aggregate( [ {$match: {fairId: Router.current().params._id} }, { $group: {_id: "$fairId", avgRank: {$avg: "$rank"}} } ]);
return Math.round(rec.avgRank * 10) / 10;
}
});
JavaScript手工计算
也是一种实时计算方法,代码量最大,但版本依赖性小。
Template.UserComments.helpers({
rankAverage: function() {
var rateNum = Comments.find().count();
if (rateNum === 0) return false;
var total = 0;
Comments.find( {} ).forEach(function(elem) {
total = total + elem.rank;
});
var avg = total / rateNum;
return Math.round(avg * 10) / 10;
}
});