mongodbmeteormeteor-publications

Meteor filtered publication with limit and skip with total count


Given a filtered and paginated meteor publication, how do I get the total count with the filtered applied?

Client Code:

import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { Track } from 'meteor/tracker';

import { Posts } from '/imports/api/posts/posts.js';

import './posts.html';

Template.App_posts.onCreated(function() {
  this.subscribe('posts.all', new Date(), 0);

  Tracker.autorun(() => {
    let postCount = Posts.find({}).count();
    console.log(postCount); // 10
  });
});

Server Code:

import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';

import { Posts } from '../posts.js';

const postsPerPage = 10;

Meteor.publish('posts.all', function(date, page = 0) {
  if (!Meteor.userId()) throw new Meteor.Error('Unauthorised');

  check(date, Date);
  check(page, Number);

  let query = {
    userId: Meteor.userId()
  };

  let options = {};

  if (date) {
    query.createdAt = date;
  }

  options.limit = postsPerPage;
  options.skip = page * postsPerPage;

  let cursor = Posts.find(query, options);

  console.log(cursor.count()); // 100

  return cursor;
});

This returns the expected posts given the date and the page but the problem is knowing the total filtered count.

Assuming there is 1000 posts, 100 of them are applicable for this date and user. How do I get the count of 100 when only 10 are returned at a time?


Solution

  • I think you should use tmeasday:publish-counts https://github.com/percolatestudio/publish-counts

    On the server, you should do:

    Meteor.publish('posts.numberOfPosts', function(date) {
       if (!this.userId){
           return this.ready();
       } 
       check(date, Date);
    
       let query = {
          userId: this.userId
       };
       if (date) {
         query.createdAt = date;
       }
       Counts.publish(this, 'all-posts', Posts.find(query));
    }
    

    And on the client: Counts.get('All-orders')

    Actually, you also may place this subscription inside "posts.all":

    Meteor.publish('posts.all', function(date, page = 0) {
      if (!Meteor.userId()) throw new Meteor.Error('Unauthorised');
    
      check(date, Date);
      check(page, Number);
    
      let query = {
        userId: Meteor.userId()
      };
    
      let options = {};
    
      if (date) {
        query.createdAt = date;
      }
    
      options.limit = postsPerPage;
      options.skip = page * postsPerPage;
    
      let cursor = Posts.find(query, options);
      // https://github.com/percolatestudio/publish-counts#noready
      Counts.publish(this, 'all-posts', Posts.find(query), {noReady: true});
    
      return cursor;
    });