Publish with reactive dependencies
Adding this package to your Meteor application augments
Meteor.publish handler object with method
related
which allows you to define publish endpoints with reactive dependencies on
additional queries. It allows easy wrapping of existing publish functions without any
change needed. You can use publish functions which return query cursors, or one which
uses publish added
/changed
/removed
API for custom publish functions.
This is useful in all situations where you want to publish documents which have a query based on data from some other document and you want that everything behaves reactively, if any of those documents change, published documents should change as well. Examples are any queries which limit published based documents on a list of IDs in another document. Or a permission system where you want to limit published documents based on flags and other properties of currently logged-in user.
Server side only.
See also the follow-up package peerlibrary:reactive-publish
which provides an alternative API through Meteor reactivity and familiar server-side autorun
.
Installation
meteor add peerlibrary:related
this.related
Along with existing properties and methods, this
inside Meteor.publish
callback now
has related
method available. Method accepts:
- a callback – a new publish callback which will get as arguments results of your queries
- one or more query cursors which should each return at most one document at any given moment;
documents returned from query cursors will then be passed to the callback reactively, every time any of them changes callback will be rerun
Example
Let's say that you have a list of blog posts user is following as follows
field in Meteor's
users
documents. You want to create a publish endpoint which will publish only those blog posts
which current user follows. But if follows
field changes, published blog posts should also
change (or if published blog posts themselves change, changes should be pushed to the client).
Meteor.publish('followed-blog-posts', function () { if (!this.userId) return; this.related(function (user) { return Posts.find({_id: {$in: user.follows}}); }, Meteor.users.find(this.userId, {fields: {follows: 1}}) ); });
Every time follows
field of currently logged-in user changes, related publish callback is
rerun with new user
document as an argument (as returned from Meteor.users.find
query).
Callback should do anything a normal publish callback should: or call added
/changed
/removed
,
or simply return a query to publish like in our example.
Documents are tracked between reruns and are not republished if they remain the same between reruns.
Known limitations
Currently each of related queries is expected to return at most one document at all times. In theory returning multiple documents could be supported, but this means that related publish callback would be rerun at any change of any of those multiple documents. This is probably not a very efficient approach.
Nested calls to related
should probably work, but were not yet tested.
Related projects
There are few other similar projects trying to address a similar feature. We needed something
production grade, with tests, and simple code base built upon existing Meteor features
instead of trying to replace them. Most of our code just wraps existing Meteor code into the
reactive loop, and allowing existing publish functions to be reused without any change needed,
you can return queries or you can use added
/changed
/removed
, all this is supported. Just
instead of having static arguments to your publish function, publish function is rerun when any
of arguments changes. Its API is thus simple and intuitive.
- meteor-reactive-publish – uses API based on server-side dependency
tracking, but no tests and no support for
added
/changed
/removed
- meteor-publish-with-relations – complicated custom API not
allowing to reuse existing publish functions, which means no support for
added
/changed
/removed
as well - meteor-smart-publish – complicated way of defining dependencies
and works only with query cursors and not custom added
/changed
/removed
functions
- reywood:publish-composite – allow you to define a nested structure
of cursors, which get documents from higher levels in a reactive manner, but it works only with only with query cursors
and not custom
added
/changed
/removed
functions - copleyjk:simple-publish – seems similar to
meteor-publish-with-relations
, but a more developed version covering more edge cases; on the other hand it has the same limitations of no support foradded
/changed
/removed