Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Publish documents in a collection to a meteor client depending on the existence of a specific document in another collection (publish-with-relations)

Tags:

meteor

publish

I have two collections

  1. Offers (relevant fields: _id)
  2. ShareRelations (relevant fields: receiverId and offerId)

and I'd like to publish only Offers to the logged in user which have been shared to him.

Actually, I'm doing this by using a helper array (visibleOffers) which I fill by looping for each ShareRelations and use this array later on the Offers.find as $in selector.

I wonder if this might be the meteor way to do this, or if I could do with less and/or prettier code?

My actual code to publish the Offers is the following:

Meteor.publish('offersShared', function () {
  // check if the user is logged in
  if (this.userId) {
    // initialize helper array
    var visibleOffers = [];
    // initialize all shareRelations which the actual user is the receiver
    var shareRelations = ShareRelations.find({receiverId: this.userId});
    // check if such relations exist
    if (shareRelations.count()) {
      // loop trough all shareRelations and push the offerId to the array if the value isn't in the array actually
      shareRelations.forEach(function (shareRelation) {
        if (visibleOffers.indexOf(shareRelation.offerId) === -1) {
          visibleOffers.push(shareRelation.offerId);
        }
      });
    }
    // return offers which contain the _id in the array visibleOffers
    return Offers.find({_id:  { $in: visibleOffers } });
  } else {
    // return no offers if the user is not logged in
    return Offers.find(null);
  }
});

Furthermore, the actual solution has the downside that if a new share relations is being created, the Offers collection on the client doesn't get updated with the newly visible offer instantly (read: page reload required. But I'm not sure if this is the case because of this publish method or because of some other code an this question is not primary because of this issue).

like image 982
Roger Schaerer Avatar asked Dec 24 '13 00:12

Roger Schaerer


1 Answers

What you are looking for is a reactive join. You can accomplish this by directly using an observe in the publish function, or by using a library to do it for you. Meteor core is expected to have a join library at some point, but until then I'd recommend using publish-with-relations. Have a look at the docs, but I think the publish function you want looks something like this:

Meteor.publish('offersShared', function() {
  return Meteor.publishWithRelations({
    handle: this,
    collection: ShareRelations,
    filter: {receiverId: this.userId},
    mappings: [{collection: Offers, key: 'offerId'}]
  });
});

This should reactively publish all of the ShareRelations for the user, and all associated Offers. Hopefully publishing both won't be a problem.

PWR is a pretty legit package - several of us use it in production, and Tom Coleman contributes to it. The only thing I'll caution you about is that as of this writing, the current version in atmosphere (v0.1.5) has a bug which will result in a fairly serious memory leak. Until it gets bumped, see my blog post about how to run an updated local copy.

update 2/5/14:

The discover meteor blog has an excellent post on reactive joins which I highly recommend reading.

like image 191
David Weldon Avatar answered Sep 18 '22 23:09

David Weldon