In Meteor, a client-only collection is a database that is kept only on client side, without being synced with server (as a normal collection would be). Because the collection is not automatically synced, we will need to manually ‘push’ changes from server to client every time we want to publish something new.
For better illustration, let’s say we want to write a simple (and silly) app that retrieve and display current server’s time.
We start by defining a client-only collection:
1 2 3 4 5 |
/******* Client Code *********************************************/ var ServerTime = new Meteor.Collection('serverTime'); /*****************************************************************/ |
Next, we define a helper publication on server:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/******* Server Code *********************************************/ // This will be used to store the subscription objects for later management var subs = { }; // The helper publication Meteor.publish('helperPublication', function() { // #1 var subscription = this; subs[subscription._session.id] = subscription; // #2 subscription.added( 'serverTime', 'a_random_id', {date: new Date()} ); // #3 subscription.onStop(function() { delete subs[subscription._session.id]; }); }); /*****************************************************************/ |
The general idea is we will have each client subscribe to a helper publication. This helper publication will help us create and maintain a set of subscription objects that represent the current clients connected to the server. Then later we can ‘push’ changes from server to clients via those subscription objects. In more details:
Step #1: Every time a client connects, the publish() method will be run. The ‘this’ inside the method represents a client subscribing to the publication. We save ‘this’ to an object named ‘subs’ for later management.
Step #2: We use the added() method to signal the client: “Hey, let’s create a new document in your client-only ‘serverTime’ collection, give it an _id of ‘a_random_id’, and then store this Date object in it”. The result: Right after subscribing to the helper function, each client will have a initial value of server time.
Step #3: We want to make sure that we will not waste time with disconnected clients, so when a client disconnects we remove it from ‘subs’.
Next, on server, we setup an interval that runs every 1 second. Each time the interval function is executed, we tell each of the subscription in subs: “Hey, remember the document with _id ‘a_random_id’ I sent you before? Now it should be changed. Please update it with this new Date object”.
1 2 3 4 5 6 7 8 9 10 11 |
/******* Server Code *********************************************/ Meteor.setInterval(function() { var currentTime = new Date(); for (var subscriptionID in subs) { var subscription = subs[subscriptionID]; subscription.changed( 'serverTime', 'a_random_id', {date: currentTime} ); } }, 1000); /*****************************************************************/ |
Finally, in client code, we have each client subscribe to the above-mention helper function:
1 2 3 4 5 |
/******* Client Code *********************************************/ Meteor.subscribe('helperPublication'); /*****************************************************************/ |
All connected clients will receive continuous update of server time, every second.
Hi,
This is a really interesting matter. But I have some difficulty to use it.
I am trying to feed a client-only minimongo db ‘subdatasets’ with subsets of data (I use aggregation) from a shared db ‘datasets’ (only datas are not shared).
Even with your clever ‘subs’ management object I couldn’t manage to do it properly.
Can you give me a hand on this?
You can find the whole thing on: http://meteorpad.com/pad/Ed3cdT94z8MDrc7GW/Feed%20sub-db%20on%20client%20side
Thanks!
It looks like I manage to make it works. But it became very foggy when ‘this._session.id’ comes.
Can you explain me what does ‘this’ refer to? My guess is ‘Meteor’ itself.
Where did you find this _session.id property and what does it refer to? Again, my guess is DDP but I find nothing about _session in Meteor’s doc. I found it in Meteor’s code source but — wow! — I did not understand.
Finally (it is related), is there a simple way to get rid of the ‘sub’ object. I don’t need it as only one user will work on the dataset?
Thanks again a lot!
Very useful, clearly written. Thanks very much
Pingback: Meteor – API REST – De tout et de rien
Thanks. I was trying to send aggregated from the server and the missing piece was a client-side collection.