Reputation: 132
I've been searching for answer to this question but sadly I don't see that will answer my question. I have an expense collection that looks like this
{ subcategory: 'Category-1', amount: 320 },
{ subcategory: 'Category-2', amount: 148 },
{ subcategory: 'Category-1', amount: 500 },
{ subcategory: 'Category-3', amount: 672 },
{ subcategory: 'Category-3', amount: 196 },
{ subcategory: 'Category-1', amount: 298 },
... etc
and I wanted to show in my summary report through my table like this
**Category Name** **Amount**
1. Category-1 1118
2. Category-2 148
3. Category-3 868
which I am then going to render these data on my table template
{{#each expensesentries}}
<tr>
<td>{{category}}</td>
<td>{{formatAmount amount}}</td>
</tr>
{{/each}} `
Thanks.
Upvotes: 0
Views: 5223
Reputation: 2474
You should take care, that your approved solution requires that all data is stored on the client. What does it mean?
If you have a collection with about 1000 or even more entries than you have to publish all these entries and store these entries on the client before you can do a group. That requires a lot of space and costs lot of performance. So if your collection must not be reactive than you should look for a server side group via aggregation. Check this stackoverflow-post:
EDIT: Basically the linked article shows everything you need. I hope you are already common with publish and subscribe?
Meteor.publish("expensesentries", function (args) {
var sub = this;
var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var pipeline = [
{ $group: {
_id: subcategory,
count: { $sum: amount }
}}
];
db.collection("server_collection_name").aggregate(
pipeline,
Meteor.bindEnvironment(
function(err, result) {
_.each(result, function(e) {
sub.added("client_collection_name", Random.id(), {
category: item._id,
amount: item.count
});
});
sub.ready();
},
function(error) {
Meteor._debug( "Error doing aggregation: " + error);
}
)
);
});
Check mongodb aggregation pipeline
If you use iron router than you should subscribe in there.
waitOn: function () {
return [Meteor.subscribe('expensesentries')];
},
In your Template:
Template.myTemplate.helpers({
expensesentries: function() {
return client_collection_name.find();
}
});
This query could also be definded in your iron-router data callback. Dont expect this to work out of the box. Read manuals of iron-router, mongodb aggregation and try to understand whats going on. Happy coding :)
Upvotes: 2
Reputation: 64312
There may be a more elegant way to do this, but give this a try:
Template.myTemplate.helpers({
expensesentries: function() {
var subs = {};
Expenses.find().forEach(function(e) {
if (subs[e.subcategory] == null)
subs[e.subcategory] = 0;
subs[e.subcategory] += e.amount;
});
var results = [];
_.each(subs, function(value, key) {
results.push({category: key, amount: value});
});
return results;
}
});
The first part aggregates the amounts by category into a single object. So subs
will look like:
{ 'Category-1': 1118, 'Category-2': 148, 'Category-3': 868 }
The second part builds an array (results
) with the necessary key-value pairs for your template. When done, it should look like:
[ { category: 'Category-1', amount: 1118 },
{ category: 'Category-2', amount: 148 },
{ category: 'Category-3', amount: 868 } ]
Upvotes: 0