Are transformed publish functions not reactive?


#1
Meteor.publish("questions", function () {
  var self = this;
  Questions.find({},{sort: {askedAt: -1}, limit: 20}).forEach(function (question) {
    var count = 0;
    if(_.has(question, "answers")){
      count = question.answers.length;
    }
    question = _.omit(question, "answers");
    question = _.extend(question, {count: count});
    self.added('question', question._id, question);
  });
  this.ready();
});

above one is my publish function, when we do transformations on the collection before publish, they are not reactive?

Other publish functions are working fine, but this one is not reactive?

or Is there anything wrong with my code?

In this case in my questions collection, I’m also saving answers.

In the home page I’m only displaying questions not answers(but want to display answers count)

so I’m transforming the collection before publishing, Is there any other better way to do it?


#2

This is an interesting question.

The official method is to use transforms on the collection definition, so it becomes:

Questions = new Mongo.Collection('questions', {
  transform: function(doc) {
    var count = 0;
    if('answers' in doc && doc.answers instanceof Array) {
      count = doc.answers.length;
      delete doc.answers;
    }
    doc.count = count;
  });

the server publish becomes:

Meteor.publish("questions", function () {
  Questions.find({}, {sort: {askedAt: -1}, limit: 20});
});

and the client subscription is:

Questions.subscribe('questions');

The advantage of this is that it all remains reactive. The disadvantages are:

  • The collection continues to contain the questions - so they are sent over the wire and potentially available to a client-side inspector. They will not be available to Blaze though, so I imagine that this isn’t too much of an issue in this case.

  • The transformed data (count, in this case case) is only available following a fetch (Blaze effectively does this for you, so count may still be referenced in a template). However, it does mean that you can’t, for example, do:

    Questions.find({}, {sort: {count: 1}});


#3

To “transform” on the server inside a publish I use observeChanges, thus the pub/sub remains entirely reactive.

Collection = new Meteor.Collection('collection_name');
if(Meteor.isServer)
{
	Meteor.publish('collection', function(query,options) {
		var self = this;
		var handler = null;
		query = query == undefined ? {} : query;
		options = options == undefined ? {} : options;
		//
		handler = Collection.find(query,options).observeChanges({
			added: function (id, doc) {
				var author = null;
				doc.author = Meteor.users.findOne({_id: doc.userId},{profile:1});
				self.added('collection_name', id, doc);
			},
			changed: function (id, fields) {
				self.changed('collection_name', id, fields);
			},
			removed: function (id) {
				self.removed('collection_name', id);
			}
		});
		self.ready();
		self.onStop(function () {
			if(handler) handler.stop();
		});
	});
}

if(Meteor.isClient)
{
	Meteor.subscribe('collection');
}

Meteor Reactivity by transformed sub-collection