问题
I want to make a publication with several additional fields, but I don't want to either use Collection.aggregate
and lose my publication updates when the collection change (so I can't just use self.added
in it either).
I plan to use Cursor.observeChanges
in order to achieve that. I have two major constraints:
- I don't want to publish all the documents fields
- I want to use some of the unpublished fields to create new ones. For example, I have a field
item
where I store an array ofitem
_id. I don't want to publish it, but I want to publish aitem_count
field with the length of my field array
Here comes the approach:
I plan to chain find queries. I never did that so I wonder if it possible. The general (simplified) query structure would be like this: http://jsfiddle.net/Billybobbonnet/1cgrqouj/ (I cant get the code properly displayed here)
Based on the count example in Meteor documentation, I store my query in a variable
handle
in order to stop the changes notification if a client unsubscribes:
self.onStop(function () {
handle.stop();
});
- I add a flag
initializing = true;
before my query and I set it totrue
just before callingself.ready();
. I use this flag to change myitemCount
variable only if it is the publication is initialized. So basically, I change myswitch
like that:
switch (field) {
case "item"
if (!initializing)
itemCount = raw_document.item.length;
break;
default:
}
I wanted to check that this approach is good and possible before committing into big changes in my code. Can someone confirm me if this is the right way to go?
回答1:
It's relatively easy to keep fields private even if they are part of the database query. The last argument to self.added
is the object being passed to the client, so you can strip/modify/delete fields you are sending to the client.
Here's a modified version of your fiddle. This should do what you are asking for. (To be honest I'm not sure why you had anything chained after the observeChanges
function in your fiddle, so maybe I'm misunderstanding you, but looking at the rest of your question this should be it. 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();
});
回答2:
To solve your first problem, you need to tell MongoDB what fields it should return in the cursor. Leave out the fields you don't want:
MyCollection.find({}, {fields: {'a_field':1}});
Solving your second problem is also pretty easy, I would suggest using the collection helpers packages. You could accomplish this easily, like so:
// Add calculated fields to MyCollection.
MyCollection.helpers({
item_count: function() {
return this.items.length;
}
});
This will be run before an object is added to a cursor, and will create properties on the returned objects that are calculated dynamically, not stored in MongoDB.
来源:https://stackoverflow.com/questions/30807390/build-a-reactive-publication-with-additional-fields-in-each-document