meteorsubscriptionsmeteor-publications

Overlapping Meteor publications


I have a meteor app which has 2 publications for posts. One for all posts and one for featured posts. There are 2 featured posts - "Post 1" and "Post 4". I show featured posts on all pages, while i paginate all posts (including the featured posts) sorted by name. When i travel between pages, the data from the 2 publications get mixed up and show incorrect results.

Here is the code:

Meteor.publish('posts', function(page) {
  const skip = parseInt(page && page !== '' ? page : 0) * 3
  return Posts.find({}, {
    limit: 3,
    skip,
    sort: {
      name: 1
    }
  });
});

Meteor.publish('featured', function() {
  return Posts.find({
    featured: true
  }, {
    sort: {
      name: 1
    }
  });
});

On the client I am subscribing to both and displaying the data in 2 loops

Template.hello.onCreated(function helloOnCreated() {
  const instance = this;
  instance.autorun(function() {
    instance.subscribe('posts', FlowRouter.getParam('page'))
    instance.subscribe('featured')
  });
});

Template.hello.helpers({
  posts() {
    return Posts.find({}, {
      limit: 3,
      sort: {
        name: 1
      }
    })
  },
  featured_posts() {
    return Posts.find({
      featured: true
    }, {
      sort: {
        name: 1
      }
    });
  }
});

HTML template is as follows:

<template name="hello">
  <h2>Featured</h2>
  {{#each featured_posts}}
    {{> post}}
  {{/each}}
  <h2>Posts</h2>
  {{#each posts}}
    {{> post}}
  {{/each}}
</template>

The problem is the data from the 2 subscriptions are getting mixed up in the display.

On page 1 it shows it correctly:

Page 1

Featured
  post 1
  post 4

All Posts
  post 1
  post 2
  post 3

but when I go to page 2

Page 2

Featured
  post 1
  post 4

All Posts  -- Should be
  post 1        post 4
  post 4        post 5
  post 5        post 6

It shows "post 1" inside the "posts" which is featured but shouldn't be on page 2. When I go to page 3, i see "post 1" and "post 4" but they should not be there.

I understand how the publications and subscriptions work and why this is happening - because the publications merges the dataset. I am wondering if there is a work around to keep them separate?


Solution

  • If I understand correctly, your pages correspond to pagination of your "All Posts" list. The "page" number is sent as your subscription parameter, so that you receive a short list of your posts.

    The difficulty here is indeed that your Client collection does not have all your documents in hand (since you limit them in your 'posts' publication), so you cannot use a similar skip logic as in the publication.

    As proposed in Meteor Guide > Paginating subscriptions, you could use the percolate:find-from-publication Atmosphere package to easily retrieve the documents that come from your 'posts' publication, and only them.

    // Server
    FindFromPublication.publish('posts', function(page) {
      // Same logic
      const skip = parseInt(page && page !== '' ? page : 0) * 3
      return Posts.find({}, {
        limit: 3,
        skip,
        sort: {
          name: 1
        }
      });
    });
    
    // Client (no change in subscription)
    Template.hello.helpers({
      posts() {
          return Posts.findFromPublication('posts', {}, {
            sort: {
              name: 1
            }
          });
        } // (no change in featured_posts)
    });