timmyg13
timmyg13

Reputation: 503

Meteor Group Collection by Field

I am trying to return a collection (Postings) grouped by a field (status). I am pretty new to mongo and meteor. The query below gives me the collections grouped by status with # of docs by that status... basically I want the same thing but have the actual documents in there.

Also, I would like to be able to publish/subscribe to this so that they reactivly update. I am creating an admin dashboard that groups all the Postings by current status.

A friend provided the following gist, but it is a bit over my head: https://gist.github.com/ryw/8827179

db.postings.group({ key: {status: 1}, initial: {sum:0}, reduce: function(doc, prev) { prev.sum += 1; } })

Thanks!

Upvotes: 2

Views: 571

Answers (2)

David Weldon
David Weldon

Reputation: 64312

If you need all of the documents on the client, then I would just publish the whole collection and let the template code group them.

client

Tracker.autorun(function() {
  if (Meteor.user()) {
    Meteor.subscribe('allPostings');
  }
});

Template.admin.helpers({
  postings: function() {
    if (Session.get('currentStatus')) {
      return Postings.find({status: Session.get('currentStatus')});
    }
  },
  statuses: function() {
    return _.uniq(_.pluck(Postings.find().fetch(), 'status'));
  }
});

Template.admin.events({
  'click .status': function() {
    Session.set('currentStatus', String(this));
  }
});
<template name="admin">
  <div class="left-panel">
    <ul>
      {{#each statuses}}
      <li class="status">{{this}}</li>
      {{/each}}
    </ul>
  </div>
  <div class="right-panel">
    <ul>
      {{#each postings}}
      <li>{{message}}</li>
      {{/each}}
    </ul>
  </div>
</template>

server

Meteor.publish('allPostings', function() {
  var user = Meteor.users.findOne(this.userId);
  if (user.isAdmin) {
    return Postings.find();
  }
});

I'm assuming you have some way to identify admin users (here I used isAdmin). I am also assuming that a posting has a status and a message.

Upvotes: 1

Serkan Durusoy
Serkan Durusoy

Reputation: 5472

Instead of using aggregate functions or map reduce operations, you could denormalize your data and store a separate collection of the groups and their counts.

You can update your counts using observe functions as in the following example from the relevant section of meteor docs:

// Keep track of how many administrators are online.
var count = 0;
var query = Users.find({admin: true, onlineNow: true});
var handle = query.observeChanges({
  added: function (id, user) {
    count++;
    console.log(user.name + " brings the total to " + count + " admins.");
  },
  removed: function () {
    count--;
    console.log("Lost one. We're now down to " + count + " admins.");
  }
});

// After five seconds, stop keeping the count.
setTimeout(function () {handle.stop();}, 5000);

This way, you can present the groups and their counts on a template and it would be reactive.

Upvotes: 0

Related Questions