I have a collection name transactions
with this schema
Schema.Transactions = new SimpleSchema({
/* other fields */
payment: {
type: Number,
label: 'Payment amount',
optional: true
},
deposit: {
type: Number,
label: 'Deposit amount',
optional: true,
},
/* other fields */
});
Now I want to subscribe to the total balance
of the collection using the formula total deposit - total payment
. How can I achieve this without aggregation (since I heard meteor doesnt support reactive aggregation yet)? Also this schema can contain tens to hundreds of thousands of data.
I need enlightment. Thanks guys!
True - there is no reactive aggregation. However, you can aggregate server-side within a method. For example doctorpangloss:mongodb-server-aggregation.
However, I need to make the result reactive. Looping on a huge amount of collection is resource overkill.
Save the aggregated data in a separate collection and update as new items are added/updated/deleted?
That would make sense but then I could have just created another collection that increments/decrements the balance on transaction creation/update. But thanks tho. Appreciate the help
The example from official docs is a reactive sum solution which does not loop nor persists:
// server: publish the current size of a collection
Meteor.publish("counts-by-room", function (roomId) {
var self = this;
check(roomId, String);
var count = 0;
var initializing = true;
// observeChanges only returns after the initial `added` callbacks
// have run. Until then, we don't want to send a lot of
// `self.changed()` messages - hence tracking the
// `initializing` state.
var handle = Messages.find({roomId: roomId}).observeChanges({
added: function (id) {
count++;
if (!initializing)
self.changed("counts", roomId, {count: count});
},
removed: function (id) {
count--;
self.changed("counts", roomId, {count: count});
}
// don't care about changed
});
// Instead, we'll send one `self.added()` message right after
// observeChanges has returned, and mark the subscription as
// ready.
initializing = false;
self.added("counts", roomId, {count: count});
self.ready();
// Stop observing the cursor when client unsubs.
// Stopping a subscription automatically takes
// care of sending the client any removed messages.
self.onStop(function () {
handle.stop();
});
});
// client: declare collection to hold count object
Counts = new Mongo.Collection("counts");
// client: subscribe to the count for the current room
Tracker.autorun(function () {
Meteor.subscribe("counts-by-room", Session.get("roomId"));
});
// client: use the new collection
console.log("Current room has " +
Counts.findOne(Session.get("roomId")).count +
" messages.");
// server: sometimes publish a query, sometimes publish nothing
Meteor.publish("secretData", function () {
if (this.userId === 'superuser') {
return SecretData.find();
} else {
// Declare that no data is being published. If you leave this line
// out, Meteor will never consider the subscription ready because
// it thinks you're using the added/changed/removed interface where
// you have to explicitly call this.ready().
return [];
}
});
What it does is calculate an initial sum/count/whatever aggregate you want, and then update as documents get added/removed/updated.
The only downside to this would be the initialization time but if you want real-time accurate data and you are already set on aggregation, this is much more efficient with continuous updates.