Collections 发布/订阅同一服务器集合的多个子集
编辑:这个问题、一些答案和一些评论包含了大量错误信息。有关发布和订阅同一服务器集合的多个子集的准确信息,请参阅。Collections 发布/订阅同一服务器集合的多个子集,collections,meteor,publish-subscribe,Collections,Meteor,Publish Subscribe,编辑:这个问题、一些答案和一些评论包含了大量错误信息。有关发布和订阅同一服务器集合的多个子集的准确信息,请参阅。 如何将服务器上单个集合的不同子集(或“视图”)发布为客户端上的多个集合 下面是一些伪代码来帮助说明我的问题: 项目服务器上的集合 假设我在服务器上有一个items集合,其中包含数百万条记录。我们还假设: 50条记录的enabled属性设置为true,并且 100条记录的processed属性设置为true 所有其他设置为false items: { "_id": "uniq
如何将服务器上单个集合的不同子集(或“视图”)发布为客户端上的多个集合 下面是一些伪代码来帮助说明我的问题:
项目
服务器上的集合
假设我在服务器上有一个items
集合,其中包含数百万条记录。我们还假设:
enabled
属性设置为true
,并且李>
processed
属性设置为true
false
items:
{
"_id": "uniqueid1",
"title": "item #1",
"enabled": false,
"processed": false
},
{
"_id": "uniqueid2",
"title": "item #2",
"enabled": false,
"processed": true
},
...
{
"_id": "uniqueid458734958",
"title": "item #458734958",
"enabled": true,
"processed": true
}
服务器代码
让我们发布同一服务器集合的两个“视图”。一个将发送一个包含50条记录的游标,另一个将发送一个包含100条记录的游标。在这个虚构的服务器端数据库中有超过4.58亿条记录,客户端不需要知道所有这些记录(实际上,在本例中,发送所有记录可能需要几个小时):
客户端代码
为了支持延迟补偿技术,我们被迫在客户机上声明单个集合项
。缺陷出现的地方应该很明显:如何区分已启用项目的项目
和已处理项目的项目
var Items = new Meteor.Collection("items");
Meteor.subscribe("enabled_items", function () {
// This will output 50, fine
console.log(Items.find().count());
});
Meteor.subscribe("processed_items", function () {
// This will also output 50, since we have no choice but to use
// the same "Items" collection.
console.log(Items.find().count());
});
我目前的解决方案包括使用monkey patching _publishCursor来允许使用订阅名称而不是集合名称。但这不会产生任何延迟补偿。每次写入都必须往返到服务器:
// On the client:
var EnabledItems = new Meteor.Collection("enabled_items");
var ProcessedItems = new Meteor.Collection("processed_items");
Meteor.publish('enabled_items', function() {
return enabledItems();
});
Meteor.publish('processed_items', function() {
return processedItems();
});
有了猴子补丁,这将起作用。但是进入离线模式,更改不会立即出现在客户端上——我们需要连接到服务器才能看到更改
正确的方法是什么
编辑:我刚刚重温了这个帖子,我意识到,就目前而言,我的问题和答案以及过多的评论都带有很多错误信息。
归根结底,我误解了发布-订阅关系。我认为,当您发布游标时,它将作为一个独立的集合降落在客户机上,而其他已发布的游标来自同一个服务器集合。这根本不是它的工作原理。其思想是,客户机和服务器都有相同的集合,但不同的是集合中的内容。pub分包合同协商哪些文件最终会提交给客户。Tom的回答在技术上是正确的,但缺少了一些细节来扭转我的假设。基于Tom的解释,我在另一个SO帖子中回答了一个类似的问题,但请记住我最初对Meteor酒吧的误解:
希望这能帮助那些遇到这个问题的人,让他们摆脱困惑 当您想查看项目时,是否可以使用相同的查询客户端
在lib目录中:
enabledItems = function() {
return Items.find({enabled: true});
}
processedItems = function() {
return Items.find({processed: true});
}
在服务器上:
// On the client:
var EnabledItems = new Meteor.Collection("enabled_items");
var ProcessedItems = new Meteor.Collection("processed_items");
Meteor.publish('enabled_items', function() {
return enabledItems();
});
Meteor.publish('processed_items', function() {
return processedItems();
});
论客户
Meteor.subscribe('enabled_items');
Meteor.subscribe('processed_items');
Template.enabledItems.items = function() {
return enabledItems();
};
Template.processedItems.items = function() {
return processedItems();
};
如果您仔细考虑一下,这样做会更好,因为如果您(本地)插入一个已启用和已处理的项目,它可以同时出现在两个列表中(而不是有两个单独的集合)
注
我意识到我有点不清楚,所以我把它扩展了一点,希望它能有所帮助。你可以像这样制作两个独立的出版物
服务器发布
Meteor.publish("enabled_items", function(){
var self = this;
var handle = Items.find({enabled: true}).observe({
added: function(item){
self.set("enabled_items", item._id, item);
self.flush();
},
changed: function(item){
self.set("enabled_items", item._id, item);
self.flush();
}
});
this.onStop(function() {
handle.stop();
});
});
Meteor.publish("disabled_items", function(){
var self = this;
var handle = Items.find({enabled: false}).observe({
added: function(item){
self.set("disabled_items", item._id, item);
self.flush();
},
changed: function(item){
self.set("disabled_items", item._id, item);
self.flush();
}
});
this.onStop(function() {
handle.stop();
});
});
var EnabledItems = new Meteor.Collection("enabled_items"),
DisabledItems = new Meteor.Collection("disabled_items");
Meteor.subscribe("enabled_items");
Meteor.subscribe("disabled_items");
客户端订阅
Meteor.publish("enabled_items", function(){
var self = this;
var handle = Items.find({enabled: true}).observe({
added: function(item){
self.set("enabled_items", item._id, item);
self.flush();
},
changed: function(item){
self.set("enabled_items", item._id, item);
self.flush();
}
});
this.onStop(function() {
handle.stop();
});
});
Meteor.publish("disabled_items", function(){
var self = this;
var handle = Items.find({enabled: false}).observe({
added: function(item){
self.set("disabled_items", item._id, item);
self.flush();
},
changed: function(item){
self.set("disabled_items", item._id, item);
self.flush();
}
});
this.onStop(function() {
handle.stop();
});
});
var EnabledItems = new Meteor.Collection("enabled_items"),
DisabledItems = new Meteor.Collection("disabled_items");
Meteor.subscribe("enabled_items");
Meteor.subscribe("disabled_items");
通过对每个集合进行单个发布/订阅,并在find
查询中利用$或,我成功地实现了一些有希望的初步结果
我们的想法是为Meteor.Collection提供一个包装器,它允许您添加“视图”,这些视图基本上是命名为游标的。但真正发生的是这些游标不是单独运行的。。。它们的选择器被提取到一起,并作为一个查询运行到一个pub-sub上
它并不完美,因为偏移/限制不适用于这种技术,但目前minimongo无论如何都不支持它
但最终它允许您声明看起来像同一集合的不同子集,但实际上它们是相同的子集。前面只是有一点抽象,让他们感觉完全分开了
例如:
// Place this code in a file read by both client and server:
var Users = new Collection("users");
Users.view("enabledUsers", function (collection) {
return collection.find({ enabled: true }, { sort: { name: 1 } });
});
或者,如果要传递参数:
Users.view("filteredUsers", function (collection) {
return collection.find({ enabled: true, name: this.search, { sort: { name: 1 } });
}, function () {
return { search: Session.get("searchterms"); };
});
参数以对象的形式给出,因为它是一个单独的发布/订阅$or组合,我需要一种方法来获得正确的参数,因为它们混合在一起
要在模板中实际使用它:
Template.main.enabledUsers = function () {
return Users.get("enabledUsers");
};
Template.main.filteredUsers = function () {
return Users.get("filteredUsers");
};
简言之,我利用了在服务器和客户机中运行相同代码的优势,如果服务器没有执行某些操作,客户机就会执行,反之亦然
最重要的是,只有您感兴趣的记录才会发送给客户。这一切都可以通过简单地使用$或您自己来实现,而无需抽象层,但是随着更多子集的添加,$或将变得非常丑陋。这有助于用最少的代码来管理它
我很快写了这篇文章来测试它,为篇幅长和缺乏文档表示歉意:
test.js
test.html
集合视图测试
{{>main}
集合视图测试
启用的项目
{{{#每个使能数据项}
- {{title}}
{{/每个}}
加工品
{{#每个processedItems}
- {{title}}
{{/每个}}
上述示例已简化。假设这两个子集不一定具有相同的属性。这可能很难想象