meteor中的平均汇总查询

好的,还是在我的玩具应用程序中,我想找出一组车主里程表的平均里程数。 这在客户端很容易,但不能缩放。 对? 但在服务器上,我并不完全知道如何完成它。

问题:

  1. 你如何在服务器上实现一些东西,然后在客户端上使用它?
  2. 你如何使用mongo的$ avg聚合函数来利用其优化的聚合函数?
  3. 或者(2)您如何在服务器上进行映射/缩减,并将其提供给客户端?

@HubertOG的build议是使用Meteor.call,这是有道理的,我做到了这一点:

# Client side Template.mileage.average_miles = -> answer = null Meteor.call "average_mileage", (error, result) -> console.log "got average mileage result #{result}" answer = result console.log "but wait, answer = #{answer}" answer # Server side Meteor.methods average_mileage: -> console.log "server mileage called" total = count = 0 r = Mileage.find({}).forEach (mileage) -> total += mileage.mileage count += 1 console.log "server about to return #{total / count}" total / count 

这似乎工作正常,但它并不是因为我可以告诉Meteor.call是一个asynchronous调用, answer将始终是一个空返回。 处理服务器上的东西似乎是一个常见的用例,我一定忽略了一些东西。 那会是什么?

谢谢!

从Meteor 0.6.5开始,收集API不支持聚合查询,因为没有(直接的)方法来对它们进行实时更新。 但是,您仍然可以自己编写它们,并在Meteor.publish使其可用,但结果将是静态的。 在我看来,这样做还是可取的,因为你可以合并多个聚合并使用客户端收集API。

 Meteor.publish("someAggregation", function (args) { var sub = this; // This works for Meteor 0.6.5 var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db; // Your arguments to Mongo's aggregation. Make these however you want. var pipeline = [ { $match: doSomethingWith(args) }, { $group: { _id: whatWeAreGroupingWith(args), count: { $sum: 1 } }} ]; db.collection("server_collection_name").aggregate( pipeline, // Need to wrap the callback so it gets called in a Fiber. Meteor.bindEnvironment( function(err, result) { // Add each of the results to the subscription. _.each(result, function(e) { // Generate a random disposable id for aggregated documents sub.added("client_collection_name", Random.id(), { key: e._id.somethingOfInterest, count: e.count }); }); sub.ready(); }, function(error) { Meteor._debug( "Error doing aggregation: " + error); } ) ); }); 

以上是一个示例分组/聚合聚合。 一些注意事项:

  • 当你这样做的时候,你自然会在server_collection_name上做一个聚合,然后把结果推送到另一个名为client_collection_name集合中。
  • 这个订阅不会被激活,并且当参数改变时可能会被更新,所以我们使用一个非常简单的循环来推动所有的结果。
  • 聚合的结果没有Mongo ObjectIDs,所以我们生成一些我们自己的任意的。
  • 聚合的callback需要用光纤封装。 我在这里使用Meteor.bindEnvironment ,但是也可以使用Future来进行更低级别的控制。

如果您开始合并这些出版物的结果,您需要仔细考虑随机生成的ID如何影响合并框。 然而,直接实现这个只是一个标准的数据库查询,除了使用Meteor API客户端更方便。

TL; DR版本 :几乎每当你从服务器推出数据时, publish一种method更可取。

有关不同聚合方式的更多信息, 请查看这篇文章

我用“聚合”方法做了这个。 (版本0.7.x)

 if(Meteor.isServer){ Future = Npm.require('fibers/future'); Meteor.methods({ 'aggregate' : function(param){ var fut = new Future(); MongoInternals.defaultRemoteCollectionDriver().mongo._getCollection(param.collection).aggregate(param.pipe,function(err, result){ fut.return(result); }); return fut.wait(); } ,'test':function(param){ var _param = { pipe : [ { $unwind:'$data' }, { $match:{ 'data.y':"2031", 'data.m':'01', 'data.d':'01' }}, { $project : { '_id':0 ,'project_id' : "$project_id" ,'idx' : "$data.idx" ,'y' : '$data.y' ,'m' : '$data.m' ,'d' : '$data.d' }} ], collection:"yourCollection" } Meteor.call('aggregate',_param); } }); 

}

如果你想反应,使用Meteor.publish而不是Meteor.call 。 在文档中有一个例子,他们在给定的房间发布消息的数量(就在this.userId的文档的正上方),你应该可以做类似的事情。

你可以使用Meteor.methods 。

 // server Meteor.methods({ average: function() { ... return something; }, }); // client var _avg = { /* Create an object to store value and dependency */ dep: new Deps.Dependency(); }; Template.mileage.rendered = function() { _avg.init = true; }; Template.mileage.averageMiles = function() { _avg.dep.depend(); /* Make the function rerun when _avg.dep is touched */ if(_avg.init) { /* Fetch the value from the server if not yet done */ _avg.init = false; Meteor.call('average', function(error, result) { _avg.val = result; _avg.dep.changed(); /* Rerun the helper */ }); } return _avg.val; });