EDIT: this question, some of the answers, and some of the comments, contain a lot of misinformation. See how Meteor collections, publications and subscriptions work for an accurate understanding of publishing and subscribing to multiple subsets of the same server collection.
How does one go about publishing different subsets (or "views") of a single collection on the server as multiple collections on the client?
Here is some pseudo-code to help illustrate my question:
items
collection on the server
Assume that I have an items
collection on the server with millions of records. Let's also assume that:
- 50 records have the
enabled
property set to true
, and;
- 100 records have the
processed
property set to true
.
All others are set to 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
}
Server code
Let's publish two "views" of the same server collection. One will send down a cursor with 50 records, and the other will send down a cursor with 100 records. There are over 458 million records in this fictitious server-side database, and the client does not need to know about all of those (in fact, sending them all down would probably take several hours in this example):
var Items = new Meteor.Collection("items");
Meteor.publish("enabled_items", function () {
// Only 50 "Items" have enabled set to true
return Items.find({enabled: true});
});
Meteor.publish("processed_items", function () {
// Only 100 "Items" have processed set to true
return Items.find({processed: true});
});
Client code
In order to support the latency compensation technique, we are forced to declare a single collection Items
on the client. It should become apparent where the flaw is: how does one differentiate between Items
for enabled_items
and Items
for processed_items
?
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());
});
My current solution involves monkey-patching _publishCursor to allow the subscription name to be used instead of the collection name. But that won't do any latency compensation. Every write has to round-trip to the server:
// On the client:
var EnabledItems = new Meteor.Collection("enabled_items");
var ProcessedItems = new Meteor.Collection("processed_items");
With the monkey-patch in place, this will work. But go into Offline mode and changes won't appear on the client right away -- we'll need to be connected to the server to see changes.
What's the correct approach?
EDIT: I just revisited this thread and I realize that, as it stands, my question and answers and plethora of comments carry a lot of misinformation.
What it comes down to is that I misunderstood the publish-subscribe relationship. I thought that when you published a cursor, it would land on the client as a separate collection from other published cursors that originated from the same server collection. This is simply not how it works. The idea is that both the client and server have the same collections, but it's what is in the collections that differs. The pub-sub contracts negotiate which documents end up on the client. Tom's answer is technically correct, but was missing a few details to turn my assumptions around. I answered a similar question to mine in another SO thread based on Tom's explanation, but keeping in mind my original misunderstanding of Meteor's pub-sub: Meteor publish/subscribe strategies for unique client-side collections
Hope this helps those who run across this thread and come away more confused than anything!
See Question&Answers more detail:
os