Publish and subscribe
These functions control how Meteor servers publish sets of records and how clients can subscribe to those sets.
Server Meteor.publish(name, func)
import { Meteor } from 'meteor/meteor'
(ddp-server/livedata_server.js, line 1476)
import { Meteor } from 'meteor/meteor'
(ddp-server/livedata_server.js, line 1476) Publish a record set.
Arguments
-
name
String -
Name of the record set. If
null
, the set has no name, and the record set is automatically sent to all connected clients. -
func
Function -
Function called on the server each time a client subscribes. Inside the function,
this
is the publish handler object, described below. If the client passed arguments tosubscribe
, the function is called with the same arguments.
To publish records to clients, call Meteor.publish
on the server with two parameters: the name of the record set, and a publish function that Meteor will call each time a client subscribes to the name.
Publish functions can return a Collection.Cursor
, in which case Meteor will publish that cursor’s documents to each subscribed client. You can also return an array of Collection.Cursor
s, in which case Meteor will publish all of the cursors.
If you return multiple cursors in an array, they currently must all be from different collections. We hope to lift this restriction in a future release.
A client will see a document if the document is currently in the published record set of any of its subscriptions. If multiple publications publish a document with the same _id
to the same collection the documents will be merged for the client. If the values of any of the top level fields conflict, the resulting value will be one of the published values, chosen arbitrarily.
// server: publish the rooms collection, minus secret info... Meteor.publish("rooms", function () { return Rooms.find({}, {fields: {secretInfo: 0}}); }); // ... and publish secret info for rooms where the logged-in user // is an admin. If the client subscribes to both streams, the records // are merged together into the same documents in the Rooms collection. // Note that currently object values are not recursively merged, so the // fields that differ must be top level fields. Meteor.publish("adminSecretInfo", function () { return Rooms.find({admin: this.userId}, {fields: {secretInfo: 1}}); }); // publish dependent documents and simulate joins Meteor.publish("roomAndMessages", function (roomId) { check(roomId, String); return [ Rooms.find({_id: roomId}, {fields: {secretInfo: 0}}), Messages.find({roomId: roomId}) ]; });
Alternatively, a publish function can directly control its published record set by calling the functions added
(to add a new document to the published record set), changed
(to change or clear some fields on a document already in the published record set), and removed
(to remove documents from the published record set). These methods are provided by this
in your publish function.
If a publish function does not return a cursor or array of cursors, it is assumed to be using the low-level added
/changed
/removed
interface, and it must also call ready
once the initial record set is complete.
Example:
// server: publish the current size of a collection Meteor.publish("counts-by-room", function (roomId) { var self = this; check(roomId, String); var count = 0; var initializing = true; // observeChanges only returns after the initial `added` callbacks // have run. Until then, we don't want to send a lot of // `self.changed()` messages - hence tracking the // `initializing` state. var handle = Messages.find({roomId: roomId}).observeChanges({ added: function (id) { count++; if (!initializing) self.changed("counts", roomId, {count: count}); }, removed: function (id) { count--; self.changed("counts", roomId, {count: count}); } // don't care about changed }); // Instead, we'll send one `self.added()` message right after // observeChanges has returned, and mark the subscription as // ready. initializing = false; self.added("counts", roomId, {count: count}); self.ready(); // Stop observing the cursor when client unsubs. // Stopping a subscription automatically takes // care of sending the client any removed messages. self.onStop(function () { handle.stop(); }); }); // client: declare collection to hold count object Counts = new Mongo.Collection("counts"); // client: subscribe to the count for the current room Tracker.autorun(function () { Meteor.subscribe("counts-by-room", Session.get("roomId")); }); // client: use the new collection console.log("Current room has " + Counts.findOne(Session.get("roomId")).count + " messages."); // server: sometimes publish a query, sometimes publish nothing Meteor.publish("secretData", function () { if (this.userId === 'superuser') { return SecretData.find(); } else { // Declare that no data is being published. If you leave this line // out, Meteor will never consider the subscription ready because // it thinks you're using the added/changed/removed interface where // you have to explicitly call this.ready(). return []; } });
Meteor will emit a warning message if you call
Meteor.publish
in a project that includes theautopublish
package. Your publish function will still work.
Read more about publications and how to use them in the [Data Loading] (http://guide.meteor.com/data-loading.html) article in the Meteor Guide.
Server this.userId
Access inside the publish function. The id of the logged-in user, or null
if no user is logged in.
This is constant. However, if the logged-in user changes, the publish function is rerun with the new value.
Server this.added(collection, id, fields)
Call inside the publish function. Informs the subscriber that a document has been added to the record set.
Arguments
-
collection
String -
The name of the collection that contains the new document.
-
id
String -
The new document's ID.
-
fields
Object -
The fields in the new document. If
_id
is present it is ignored.
Server this.changed(collection, id, fields)
Call inside the publish function. Informs the subscriber that a document in the record set has been modified.
Arguments
-
collection
String -
The name of the collection that contains the changed document.
-
id
String -
The changed document's ID.
-
fields
Object -
The fields in the document that have changed, together with their new values. If a field is not present in
fields
it was left unchanged; if it is present infields
and has a value ofundefined
it was removed from the document. If_id
is present it is ignored.
Server this.removed(collection, id)
Call inside the publish function. Informs the subscriber that a document has been removed from the record set.
Arguments
-
collection
String -
The name of the collection that the document has been removed from.
-
id
String -
The ID of the document that has been removed.
Server this.ready()
Call inside the publish function. Informs the subscriber that an initial, complete snapshot of the record set has been sent. This will trigger a call on the client to the onReady
callback passed to Meteor.subscribe
, if any.
Server this.onStop(func)
Call inside the publish function. Registers a callback function to run when the subscription is stopped.
Arguments
-
func
Function -
The callback function
If you call observe
or observeChanges
in your publish handler, this is the place to stop the observes.
Server this.error(error)
Call inside the publish function. Stops this client's subscription, triggering a call on the client to the onStop
callback passed to Meteor.subscribe
, if any. If error
is not a Meteor.Error
, it will be sanitized.
Arguments
-
error
Error -
The error to pass to the client.
Server this.stop()
Call inside the publish function. Stops this client's subscription and invokes the client's onStop
callback with no error.
Server this.connection
Access inside the publish function. The incoming connection for this subscription.
Client Meteor.subscribe(name, [arg1, arg2...], [callbacks])
import { Meteor } from 'meteor/meteor'
(ddp-client/livedata_connection.js, line 537)
import { Meteor } from 'meteor/meteor'
(ddp-client/livedata_connection.js, line 537) Subscribe to a record set. Returns a handle that provides stop()
and ready()
methods.
Arguments
-
name
String -
Name of the subscription. Matches the name of the server's
publish()
call. -
arg1, arg2...
EJSON-able Object -
Optional arguments passed to publisher function on server.
-
callbacks
Function or Object -
Optional. May include
onStop
andonReady
callbacks. If there is an error, it is passed as an argument toonStop
. If a function is passed instead of an object, it is interpreted as anonReady
callback.
When you subscribe to a record set, it tells the server to send records to the client. The client stores these records in local Minimongo collections, with the same name as the collection
argument used in the publish handler’s added
, changed
, and removed
callbacks. Meteor will queue incoming records until you declare the Mongo.Collection
on the client with the matching collection name.
// okay to subscribe (and possibly receive data) before declaring // the client collection that will hold it. assume "allplayers" // publishes data from server's "players" collection. Meteor.subscribe("allplayers"); ... // client queues incoming players records until ... ... Players = new Mongo.Collection("players");
The client will see a document if the document is currently in the published record set of any of its subscriptions. If multiple publications publish a document with the same _id
for the same collection the documents are merged for the client. If the values of any of the top level fields conflict, the resulting value will be one of the published values, chosen arbitrarily.
Currently, when multiple subscriptions publish the same document only the top level fields are compared during the merge. This means that if the documents include different sub-fields of the same top level field, not all of them will be available on the client. We hope to lift this restriction in a future release.
The onReady
callback is called with no arguments when the server marks the subscription as ready. The onStop
callback is called with a Meteor.Error
if the subscription fails or is terminated by the server. If the subscription is stopped by calling stop
on the subscription handle or inside the publication, onStop
is called with no arguments.
Meteor.subscribe
returns a subscription handle, which is an object with the following properties:
- stop()
-
Cancel the subscription. This will typically result in the server directing the client to remove the subscription’s data from the client’s cache.
- ready()
-
True if the server has marked the subscription as ready. A reactive data source.
- subscriptionId
-
The
id
of the subscription this handle is for. When you runMeteor.subscribe
inside ofTracker.autorun
, the handles you get will always have the samesubscriptionId
field. You can use this to deduplicate subscription handles if you are storing them in some data structure.
If you call Meteor.subscribe
within a reactive computation, for example using Tracker.autorun
, the subscription will automatically be cancelled when the computation is invalidated or stopped; it is not necessary to call stop
on subscriptions made from inside autorun
. However, if the next iteration of your run function subscribes to the same record set (same name and parameters), Meteor is smart enough to skip a wasteful unsubscribe/resubscribe. For example:
Tracker.autorun(function () { Meteor.subscribe("chat", {room: Session.get("current-room")}); Meteor.subscribe("privateMessages"); });
This subscribes you to the chat messages in the current room and to your private messages. When you change rooms by calling Session.set("current-room",
"new-room")
, Meteor will subscribe to the new room’s chat messages, unsubscribe from the original room’s chat messages, and continue to stay subscribed to your private messages.
© 2011–2017 Meteor Development Group, Inc.
Licensed under the MIT License.
https://docs.meteor.com/v1.3.5/api/pubsub.html