17

I have a publish function as follows:

Meteor.publish('tasks', function (name) {
    var project = Projects.findOne({name: name});

    return Tasks.find({projectId: project._id});
});

Now assume that at some point changes are made to Projects with the result that the above Projects.findOne returns a different project and so the Tasks.find will return other tasks. However the changes made to Projects doesn't republish the tasks

I've used reactivePublish, but it turns out the package has issues (and also does not have any unit tests). So, is there an easy way to make this publish function re-publish when project changes ?

Jeanluca Scaljeri
  • 26,343
  • 56
  • 205
  • 333
  • possible duplicate of [Publish documents in a collection to a meteor client depending on the existance of a specific document in another collection (publish-with-relations)](http://stackoverflow.com/questions/20753279/publish-documents-in-a-collection-to-a-meteor-client-depending-on-the-existance) – David Weldon Oct 16 '14 at 08:05
  • Why should you republish it? The cursor you return is Tasks. If you Tasks is changed, it should be automatically published. – waitingkuo Oct 16 '14 at 08:06
  • I was actually looking for an answer without the use of some kind of plugin. For example, the answer in the other post suggests to use [meteor-publish-with-relations](https://github.com/svasva/meteor-publish-with-relations) This project was last modified a year ago. It will probably give me at some point the same issues I have now with reactivePublish – Jeanluca Scaljeri Oct 16 '14 at 08:34
  • what are you subscribing to? Does the name change reactively in your subscribe? – Christian Fritz Oct 16 '14 at 13:29
  • good point, it wasn't very clear. I've improved the question – Jeanluca Scaljeri Oct 16 '14 at 14:00
  • I'm not sure it will work (so I'm not posting it as an answer), but have you tried wrapping the `findOne` in a `Tracker.autorun`? – Christian Fritz Oct 16 '14 at 15:51
  • Never heard of Tracker, seems like a replacement of Deps, is it ? Furthermore, Tracker seems to only work on the client! – Jeanluca Scaljeri Oct 16 '14 at 18:21
  • You should be able to get this done using the added/changed/removed interface for `publish`. See the second, long example in the documentation for `publish`. – Christian Fritz Oct 17 '14 at 04:11

2 Answers2

23

Overview

As of this writing, reactive joins are an unsolved problem. For a complete overview see Reactive Joins In Meteor.

Recommendations

I strongly recommend against using observeChanges directly. It's incredibly hard to get right, and easy to develop a memory leak. If you don't believe me, watch this video on EventedMind. It will make your eyes bleed.

There are several package-based solutions to this problem. The meteor guide recommends publish-composite.

If you find the idea of using a package-based solution to be unacceptable, have a close look at the Joining On The Client section from Reactive Joins In Meteor. It's clean but requires more waiting on the user's part. Also see my post on template joins if you prefer to active your subscriptions at the template level.

David Weldon
  • 63,632
  • 11
  • 148
  • 146
  • The problem with the available packages is that they have issues or no documentation (not to mention unit tests). So until this is part of meteor I'll fix it on the client. Thnx! – Jeanluca Scaljeri Oct 17 '14 at 19:41
  • The code in the Reactive Joins in Meteor article seems to have gone stale with changes to iron-router's API. Is there any way we could get a code snippet that works in current versions? – RoyalTS Jan 29 '15 at 10:33
  • 3
    In the meantime, [smart-publish has advised to avoid using it in production](https://github.com/yeputons/meteor-smart-publish/#meteor-smart-publish). Looks like [reywood:publish-composite is the leader nowadays](https://atmospherejs.com/reywood/publish-composite). – Dan Dascalescu Jun 19 '15 at 00:09
  • Yes, I've been meaning to update this answer. Thanks Dan. – David Weldon Jun 19 '15 at 00:14
6

There is a new kid on the block now. A full server-side reactive publish solution. (Disclaimer: I am one of the authors.) It is designed so that you can use it normally as you would expect with autorun. It takes care of everything automatically.

Install the package by calling meteor add peerlibrary:reactive-publish.

With the package added you can then simply do:

Meteor.publish('tasks', function (name) {
    this.autorun(function (computation) {
        var project = Projects.findOne({name: name}, {fields: {_id: 1}});

        return Tasks.find({projectId: project._id});
    });
});

Exactly as you would expect. :-)

The important part is to limit fields in the first query only to _id, otherwise autorun will be rerun every time any field of the project document changes. You do not want that.

Tim
  • 4,217
  • 1
  • 15
  • 21
Mitar
  • 6,756
  • 5
  • 54
  • 86