There are several solutions out there for subscription paging, but I never really looked into any of them because some time ago I had devised my own solution. Over the years I became more and more disenchanted with my approach, because it seemed overly complex
Originally I did something like this
Publication = new Mongo.Collection('publication');
Meteor.publish('publication', function(query, skip){
const self = this;
const maxCount = Publication.find(query).count();
const handler = Publication.find(query, {skip: skip, limit: 8}).observeChanges({
added: function(id, object) {
object._subscriptionId = self._subscriptionId;
object.maxCount = maxCount;
self.added('publication', id, object);
},
changed: function(id, fields) {
self.changed('publication', id, fields);
},
removed: function(id) {
// console.log('business.removed',id);
self.removed('publication', id);
}
});
self.ready();
self.onStop(function() {
if (handler) {
handler.stop();
}
});
});
on the client side I would then grab one of the objects in a callback of the subscription to setup the pagination
subscribe('publication', query, skip, function(){
const object = Publication.findOne();
// feed object.maxCount to the pagination
});
This approach also had the advantage that I was able to tell my subscriptions apart on the client by filtering for _subscriptionId
.
Long story short I wanted to simplify my approach, and also get away from observeChanges
for every subscription to Publication
, so I came up with the following, which works surprisingly well
Publication = new Mongo.Collection('publication');
PublicationCount = new Mongo.Collection('publication_count');
Meteor.publish('publication', function(query, skip){
const self = this;
// get the max count for the query without limit
const maxCount = Publication.find(query).count();
// see if there is an entry in PublicationCount for this connection id
const pubcount = PublicationCount.findOne({connectionId: self.connection.id});
var pubcountId = null;
if(pubcount) {
// update if exists
PublicationCount.update(pubcount._id, {$set:{maxCount: maxCount}});
pubcountId = pubcount._id;
} else {
// create if it did not
pubcountId = PublicationCount.insert({connectionId: self.connection.id, maxCount: maxCount});
}
//
// return array of cursors
//
return [
Publication.find(query,{skip: skip, limit: 8}),
PublicationCount.find(pubcountId),
];
});
//
// use Meteor.onConnection to clean up PublicationCount for disconnected connections
//
Meteor.onConnection(function(connection) {
const connectionId = connection.id;
connection.onClose(function(){
let c = PublicationCount.remove({connectionId: connectionId});
console.log(`onClose ${connectionId} removed ${c}`);
});
});
//
// clean out PublicationCount when server starts
//
Meteor.startup(function(){
PublicationCount.remove({});
});
On the client side I simply subscribe and read the count for the pagination
subscribe('publication', query, skip, function(){
const count = PublicationCount.findOne();
if(count) {
// set up pagination with count.maxCount
}
});
I would be interested what you think about this approach.