Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Publishing/subscribing multiple subsets of the same server collection

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:

  1. 50 records have the enabled property set to true, and;
  2. 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!

like image 579
matb33 Avatar asked Sep 28 '12 01:09

matb33


Video Answer


1 Answers

Could you not just use the same query client-side when you want to look at the items?

In a lib directory:

enabledItems = function() {   return Items.find({enabled: true}); } processedItems = function() {   return Items.find({processed: true}); } 

On the server:

Meteor.publish('enabled_items', function() {   return enabledItems(); }); Meteor.publish('processed_items', function() {   return processedItems(); }); 

On the client

Meteor.subscribe('enabled_items'); Meteor.subscribe('processed_items');  Template.enabledItems.items = function() {   return enabledItems(); }; Template.processedItems.items = function() {   return processedItems(); }; 

If you think about it, it is better this way as if you insert (locally) an item which is both enabled and processed, it can appear in both lists (a opposed to if you had two separate collections).

NOTE

I realised I was kind of unclear, so I've expanded this a little, hope it helps.

like image 182
Tom Coleman Avatar answered Sep 19 '22 09:09

Tom Coleman