DarkMatter in Cyberspace
  • Home
  • Categories
  • Tags
  • Archives

在Meteor应用中计算用户评分平均值


以下方法使用的客户端展现代码(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;
  }
});


Published

Feb 8, 2015

Last Updated

Feb 8, 2015

Category

Tech

Tags

  • average 1
  • meteor 47
  • mongodb 24

Contact

  • Powered by Pelican. Theme: Elegant by Talha Mansoor