Create a reactive publication with additional fields in each document.

I want to make a publication with several additional fields, but I do not want to use Collection.aggregate and lose publication updates when changing the collection (so I cannot just use self.added in it).

I plan to use Cursor.observeChanges to achieve this. I have two main limitations:

  • I do not want to publish all document fields.
  • I want to use some unpublished fields to create new ones. For example, I have an item field where I store an array of item _id. I do not want to publish it, but I want to publish the item_count field with the length of my field array

Here's the approach:

  • I am planning a search query chain. I have never done this, so I wonder if this is possible. The general (simplified) structure of requests will look like this: http://jsfiddle.net/Billybobbonnet/1cgrqouj/ (I can not display the code correctly here)

  • Based on the counting example in the Meteor documentation , I save my request in the handle variable to stop notification changes if the client does not sign:

    self.onStop(function () { handle.stop(); });

  • I add the flag initializing = true; before my request, and I set it to true just before calling self.ready(); . I use this flag to change my itemCount variable only if it is initialized by publication. So basically I change my switch as follows:

    switch (field) { case "item" if (!initializing) itemCount = raw_document.item.length; break; default: }

I wanted to verify that this approach is good and feasible before making big changes to my code. Can someone confirm me if this is the right way?

0
source share
2 answers

It is relatively easy to keep fields private, even if they are part of a database query. The last argument to self.added is the object passed to the client, so you can delete / modify / delete the fields that you send to the client.

The version of your violin has been changed here. This should do what you ask. (Honestly, I'm not sure why you had something in the chain after the observeChanges function in your fiddle, so maybe I don’t understand you, but looking at the rest of your question, it should be like that. Sorry if I got it wrong.)

 var self = this; // Modify the document we are sending to the client. function filter(doc) { var length = doc.item.length; // White list the fields you want to publish. var docToPublish = _.pick(doc, [ 'someOtherField' ]); // Add your custom fields. docToPublish.itemLength = length; return docToPublish; } var handle = myCollection.find({}, {fields: {item:1, someOtherField:1}}) // Use observe since it gives us the the old and new document when something is changing. // If this becomes a performance issue then consider using observeChanges, // but its usually a lot simpler to use observe in cases like this. .observe({ added: function(doc) { self.added("myCollection", doc._id, filter(doc)); }, changed: function(newDocument, oldDocument) // When the item count is changing, send update to client. if (newDocument.item.length !== oldDocument.item.length) self.changed("myCollection", newDocument._id, filter(newDocument)); }, removed: function(doc) { self.removed("myCollection", doc._id); }); self.ready(); self.onStop(function () { handle.stop(); }); 
+3
source

To solve your first problem, you need to tell MongoDB which fields it should return in the cursor. Leave the fields you do not want:

 MyCollection.find({}, {fields: {'a_field':1}}); 

The solution to the second problem is also quite simple, I would suggest using collections of package helpers . You can do it easily, for example:

 // Add calculated fields to MyCollection. MyCollection.helpers({ item_count: function() { return this.items.length; } }); 

This will be performed before the object is added to the cursor, and will create properties of the returned objects, which will be calculated dynamically and not stored in MongoDB.

+1
source

All Articles