Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Iron Router to waitOn subscription that's dependent on data from a doc that will come from another subscription

I'm having trouble configuring the waitOn portion of a route where one of the subscription's parameters is determined by the value from a doc that comes from a different subscription.

The collections in play are Candidates and Interviews. An interview will have one and only one candidate. Here's some sample data:

candidate = {
    _id: 1
    firstName: 'Some',
    lastName: 'Developer'
    //other props
};

interview = { 
    _id: 1,
    candidateId: 1
    //other props
};

The route is configured as follows.

this.route('conductInterview', {
    path: '/interviews/:_id/conduct', //:_id is the interviewId
    waitOn: function () {
        return [
            Meteor.subscribe('allUsers'),
            Meteor.subscribe('singleInterview', this.params._id),
            // don't know the candidateId to lookup because it's stored
            // in the interview doc
            Meteor.subscribe('singleCandidate', ???), 
            Meteor.subscribe('questions'),
            Meteor.subscribe('allUsers')
        ];
    },
    data: function () {
        var interview = Interviews.findOne(this.params._id);
        return {
            interview: interview,
            candidate: Candidates.findOne(interview.candidateId);
        };
    }
});

The problem is that I don't have a candidateId to pass to the singleCandidate subscription in the waitOn method because it's stored in the interview doc.

I've thought of two possible solutions, but I don't really like either of them. The first is to change the route to something like /interviews/:_id/:candidateId/conduct. The second is to denormalize the data and store the candidate's info in the interview doc.

Are there any other options to accomplish this besides those two?

like image 519
Craig M Avatar asked Feb 17 '14 21:02

Craig M


3 Answers

You may get some ideas by reading this post on reactive joins. Because you need to fetch the candidate as part of the route's data, it seems like the easiest way is just to publish both the interview and the candidate at the same time:

Meteor.publish('interviewAndCandidate', function(interviewId) {
  check(interviewId, String);

  var interviewCursor = Interviews.find(interviewId);
  var candidateId = interviewCursor.fetch()[0].candidateId;

  return [interviewCursor, Candidates.find(candidateId);];
});

However, this join is not reactive. If a different candidate gets assigned to the interview, the client will not be updated. I suspect that isn't a problem in this case though.

like image 134
David Weldon Avatar answered Oct 31 '22 16:10

David Weldon


You can change your publish function singleCandidate to take interviewId as paramater instead of candidateId and pass this.params._id

like image 40
Serkan Durusoy Avatar answered Oct 31 '22 18:10

Serkan Durusoy


I had similar problem I managed to solve it via callback in subscribe

http://docs.meteor.com/#/basic/Meteor-subscribe

For example you have user data with city ids, and you need to get city objects

 waitOn: ->
    router = @
    [
        Meteor.subscribe("currentUserData", () ->
          user = Meteor.user()
          return unless user
          cityIds = user.cityIds
          router.wait( Meteor.subscribe("cities", cityIds)) if cityIds        
        )
    ]
like image 22
radzserg Avatar answered Oct 31 '22 17:10

radzserg