Question

I'm trying to route to one page if something exists, and another if it doesn't. However, I don't want to subscribe to the entire collection (~thousands), because I think it will affect performance. How do I do this?

I tried something like this, but for some reason Meteor goes through the router code twice on pageload and flashes the error page briefly before redirecting to the item page, and I don't want this to happen.

Here's what I have:

router.coffee

to: (id)->
  Meteor.subscribe 'item', id
  item = Items.findOne id
  if item
    # if the item exists, then redirect to it
    Session.set 'currentItemId', id
    'itemPage'
  else
    # if not, then redirect to the sorry page
    'sorryPage'

publications.coffee

Meteor.publish 'item', (id)->
  return Items.find({_id: id})

Subscribing to the entire collection will affect performance, right? Is there an easier way to check existence within a collection without subscribing to it? I tried to do a Meteor.call to check it server side, but it didn't work and isn't ideal (router waiting on server call..). Is there a "right" way to do this?

Was it helpful?

Solution

The reason you're getting this "flashing" effect is probably because your router is implemented to be reactive (I'm not sure if this is a right strategy BTW) and since you're using Items.findOne, this method invalidates the current computation as soon as the data requested by Meteor.subscribe arrives to the Items collection.

Also, note that every subscription within an active computation get's cancelled automatically as soon as the computation gets recomputed. However, as it is claimed in the documenation (look here) Meteor should be smart enough to detect when you subscribe to the same data set twice, so this should not have any side effects.

If I were you, I would consider changing my router logic to something like this:

Session.set('currentItemId', id);
var status = Session.get('currentItemStatus');    
if (status === 'ready')
    return 'itemPage';
if (status === 'missing')
    return 'sorryPage';
return 'loadingPage'; // probably status === 'loading'

And then, somewhere else in the project I would do:

Deps.autorun(function () {
    Session.set('currentItemStatus', 'loading');  
    Meteor.subscribe('item', Session.get('currentItemId'), function () {
        // onReady callback
        var item = Items.findOne({_id:id});
        if (item)
            Session.set('currentItemStatus', 'ready');
        else
            Session.set('currentItemStatus', 'missing');
    });
});

Please note, that if currentItemId does not change, the computation defined Deps.autorun will not be invalidated, so no unnecessary loadingPage will be shown to the user.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top