If I understand you right, you want every feed to have lastActivity
field which contains timestamp of last submitted feed element of this feed. You want this field to be reactive and you don't want to publish all feed elements.
In this case, aggregation is not a solution, because Meteor does not allow reactive aggregations.
You need to use low-level publish API: http://docs.meteor.com/#/full/meteor_publish (see example section).
Low-level publish API (this.added
/this.removed
/this.changed
/others) gives you full control of what data you send to client via Meteor.publish
method.
Here is how you can solve your problem (I use ES2015 syntax):
// client/client.js
Meteor.subscribe('userFeeds', { userId: 1 });
// lib/lib.js
Feeds = new Mongo.Collection('feeds');
FeedElements = new Mongo.Collection('FeedElements');
// server/server.js
// When setting `submitted` field, automatically set `submittedAt` field
// (I use matb33:collection-hooks here)
FeedElements.before.update((userId, elem, fieldNames, modifier) => {
if (modifier.$set.submitted) {
modifier.$set.submittedAt = new Date();
}
});
function getLastActivity(feedId) {
const lastSubmittedElem = FeedElements.findOne(
{
feedId,
submitted: true,
},
{
sort: { submittedAt: -1 }
}
);
return lastSubmittedElem ? lastSubmittedElem.submittedAt : null;
}
Meteor.publish('userFeeds', function({ userId }) {
const elemsObservers = {};
// Observe all user feeds
var feedObserver = Feeds.find({ userId: userId }).observeChanges({
added: (feedId, fields) => {
// Observe feed elements of the feed
elemsObservers[feedId] = FeedElements.find({ feedId }).observeChanges({
changed: (elemId, fields) => {
// Update `lastActivity` field when new element is submitted
if (fields.submitted) {
this.changed('feeds', feedId, { lastActivity: fields.submittedAt });
}
},
});
fields.lastActivity = getLastActivity(feedId);
this.added('feeds', feedId, fields);
},
changed: (feedId, fields) => {
this.changed('feeds', feedId, fields);
},
removed: (feedId) => {
elemsObservers[feedId].stop();
delete elemsObservers[feedId];
this.removed('feeds', feedId);
},
});
this.ready();
this.onStop(function() {
feedObserver.stop();
for (const feedId in elemsObservers) {
elemsObservers[feedId].stop();
}
});
});
Also I prepared github repo https://github.com/imkost/feeds. Just git clone
and meteor run
.