Keeping 2 publications from same collection independent?

I’m working on an image database. I want one image to be featured on top of a gallery, on the first page.

There are 2 subscriptions:

  • pix.pinned.public for the single featured image
  • pix.paged-gallery.public for the paged gallery, containing 24 images per page

Both publications use the same collection EboyPix.

Unfortunately the featured image does always shows up twice:

  • on top (good, this is where it should go)
  • added to the gallery of 24 (even in cases it should be on a page other that page 1)

So in some cases the gallery will show 24 images, in other cases it will show 25 images:

  • 24 (good): when the featured image is part of page 1 of the gallery
  • 25 (bad): when the featured image is part of page 2+ of the gallery — but is added to the 24 images on page 1 (because we’re subscribed to both subscriptions, which are actually one collection).

Ideally I’d like to publish the featured image collection under a different name (so it doesn’t interfere with the gallery collection). This doesn’t seem to be possible though.

And the client side collection EboyPix has no notion of which page each image should go on. So it doesn’t seem possible to filter out images from page 2+ (which the featured image might be from).

This is very confusing to me, any help is greatly appreciated!

Thanks! :slight_smile:

Publications:

// Pinned
Meteor.publish('pix.pinned.public', function pixPinnedPublic() {
  const selector = { projects: 'pinned' };
  return EboyPix.find(selector);
});

// Paged Gallery
Meteor.publish('pix.paged.public', function pixPagedPublic(slug, page, query) {
  // Build selector
  const selector = urlToSelector(slug, query);
  const pixPerPage = 24;
  // Convert page string to integer so we can do some math
  let pageInt = parseInt(page, 10);
  const skipCount = (pageInt - 1) * pixPerPage;
  const options = {
    limit: pixPerPage,
    skip: skipCount,
    sort: { createdAt: -1 }
  };
  return EboyPix.find(selector, options);
});

Subscriptions:

Template.pixPoolPage.onCreated(function() {
  const self = this;
  self.autorun(function() {
    const thisPage = FlowRouter.getParam('page');
    const thisSlug = FlowRouter.getParam('slug');
    const searchQuery = FlowRouter.getQueryParam('q');
    self.subscribe('pix.paged.public', thisSlug, thisPage, searchQuery);
  });
});

Template.picPinned.onCreated(function() {
  const self = this;
  if (isHome()) {
    self.autorun(function() {
      self.subscribe('pix.pinned.public');
    });
  }
});

That is the expected behaviour of Meteor’s “merge box”, which ensures that the client gets any and all qualifying documents in the local minimongo collection.

You say it doesn’t seem possible to filter out the pinned image, but it’s been selected for publication by the { projects: 'pinned' } selector. You are publishing all fields, so can you filter it out on the client from the collection? So the gallery images are selected on the client by { projects: { $ne: 'pinned' } }.

3 Likes

If you can make do without having your pinned image in the general gallery as well, use { projects: { $ne: 'pinned' } } on both server (in the query in the publication) and on the client query.

If you want the pinned image to take it’s correct place in the general gallery as well as sit in the pinned position, you might need some selector like this on the client:

{ createdAt: { $gte: minimumCreatedAtValue, $lte: maximumCreatedAtValue }}

where the minimumCreatedAtValue and maximumCreatedAtValue are found on the client using a query with { projects: { $ne: 'pinned' } } in it.

It’s a bit ugly, as you’re using three queries on the client that way, instead of one, but it looks like createdAt is the field that you’re sorting on, so you’re going to have to use that to somehow keep the pinned photo in or out of the gallery.

2 Likes

Yes, I tried { projects: { $ne: 'pinned' } } — but then the ‘pinned’ image wouldn’t show up on gallery page 1, even if it were part of page 1.

Cropping off anything older than the newest 24 images turns out to work:

const options = {
  limit: 24,
  sort: { createdAt: -1 }
};

Thanks again! :slight_smile: