感谢您促使我写出更清晰的解释。这里是一个带有我的注释的完整示例。我已经清理了一些错误和不一致之处。下一个文档发布将使用此内容。
Meteor.publish
非常灵活。它不仅限于向客户端发布现有的MongoDB集合:我们可以发布任何我们想要的东西。具体来说,Meteor.publish
定义了客户端可以订阅的一组文档。每个文档都属于某个集合名称(一个字符串),具有唯一的_id
字段,然后具有一些JSON属性集。随着集合中的文档发生变化,服务器将向每个订阅的客户端发送更改,使客户端保持最新状态。
我们将在这里定义一个文档集,称为“counts-by-room”,其中包含名为“counts”的集合中的单个文档。该文档将有两个字段:一个带有房间ID的“roomId”和“count”:该房间中消息的总数。没有真正的MongoDB集合名为“counts”。这只是我们的Meteor服务器将向客户端发送并存储在名为“counts”的客户端侧集合中的集合名称。
为此,我们的发布函数需要一个“roomId”参数,该参数将来自客户端,并观察该房间中所有消息(在其他地方定义)。我们可以使用更有效的“observeChanges”形式来观察这里的查询,因为我们不需要完整的文档,只需要知道是否添加或删除了新文档。每当添加一个具有我们感兴趣的“roomId”的新消息时,我们的回调函数会增加内部计数,然后向客户端发布具有更新总数的新文档。当删除消息时,它会减少计数并向客户端发送更新。
当我们第一次调用
observeChanges
时,一些
added
回调函数将立即运行,对于已经存在的每个消息。然后,未来的更改将在添加或删除消息时触发。
我们的发布功能还会注册一个
onStop
处理程序,在客户端取消订阅(手动或断开连接)时清理。该处理程序会从客户端中删除属性并拆除正在运行的
observeChanges
。
每当新客户端订阅
"counts-by-room"
时,发布函数都会运行,因此每个客户端都将有一个代表它的
observeChanges
运行。
Meteor.publish("counts-by-room", function (roomId) {
var self = this;
var count = 0;
var initializing = true;
var handle = Messages.find({room_id: roomId}).observeChanges({
added: function (doc, idx) {
count++;
if (!initializing)
self.changed("counts", roomId, {count: count});
},
removed: function (doc, idx) {
count--;
self.changed("counts", roomId, {count: count});
}
});
initializing = false;
self.added("counts", roomId, {count: count});
self.ready();
self.onStop(function () {
handle.stop();
});
});
现在,在客户端,我们可以像处理典型的Meteor订阅一样处理它。首先,我们需要一个
Mongo.Collection
来保存我们计算出的计数文档。由于服务器正在发布到名为
"counts"
的集合中,因此我们将
"counts"
作为参数传递给
Mongo.Collection
构造函数。
// client: declare collection to hold count object
Counts = new Mongo.Collection("counts")
然后我们可以订阅。 (实际上,在声明集合之前,您可以订阅:Meteor将排队等待传入的更新,直到有地方放置它们。) 订阅的名称是"counts-by-room"
,它需要一个参数:当前房间的ID。我将其包装在Deps.autorun
中,以便随着Session.get('roomId')
的更改,客户端将自动取消订阅旧房间的计数并重新订阅新房间的计数。
Tracker.autorun(function () {
Meteor.subscribe("counts-by-room", Session.get("roomId"));
});
最后,我们已经获得了在
Counts
中的文档,并且我们可以像客户端上的其他Mongo集合一样使用它。任何引用此数据的模板都会在服务器发送新计数时自动重新绘制。
// client: use the new collection
console.log("Current room has " + Counts.findOne().count + " messages.");
added
函数中的self.flush();
将在集合填充时将该订阅推送到客户端。想象一下,如果在“room_id”中有1,000,000条“消息”,那么您将收到从计数1开始到计数1,000,000结束的1,000,000个订阅。这将会使您的浏览器锁定相当长的时间!更不用说通过网络传输的数据量了... - matb33added
函数中调用self.flush();
的频率,例如: clearTimeout(t); t = setTimeout(function () { self.flush(); }, 10); - matb33