MongoDB's find method allows us to specify a projection, i.e., what fields should be included in or omitted from the result set. Meteor, connected to a database on both the server side and client side, can benefit from using projection in two major and different ways.

Published Cursor Projection (Server-side)

The benefits of using projection on a published cursor are fairly straightforward; two main use cases here:

  • bandwidth optimisation: send less data down the wire
  • security: prevent sensitive data from being sent to the client

Nothing to surprise you here.

Minimongo Projection (Client-side)

This is where things get a little more interesting. Obviously, since the data has already been loaded on the client side, we don't have to concern ourselves with network traffic or bandwidth. Similarly, if server is sending any sensitive data, now it's too late to do anything about that. What good can projecting fields do us on the client side then?

A lot, in fact! You see, in my experience Meteor's minimongo makes it quite easy to forget about any optimisations and just fetch whole documents in template helpers. And this is actually fine and convenient in the beginning but it may lead to severe performance problems if your template helpers run expensive queries (because every update of the document will trigger the query to be reactively re-run).

Projection gives us a big win in that if we exclude fields in a cursor in a template helper (or generally in any Tracker.autorun context), Meteor's reactivity will not trigger when the excluded fields change.

var coll = new Mongo.Collection(null);  
coll.insert({who: 'Darth Vader', what: 'father'});

// Set up a reactive callback (projection via `fields` option).
Tracker.autorun(function() {  
  console.log('reactively called');
  coll.find({}, {fields: {who: 1}}).fetch();
});

// Update excluded field.
var item = coll.find().fetch()[0];  
coll.update(item._id, {$set: {what: 'son'}});  
// no log output

// Update included field.
coll.update(item._id, {$set: {who: 'Luke Skywalker'}});  
// "reactively called"

Which means we can only project the fields we actually need in a template helper and we can rest assured our helper will be called when any of those fields are updated but not when other fields change. In other words, we can move reactivity from document level to field level!

In certain - and actually quite common - cases, projecting only a subset of document's fields in reactive contexts will help your app's client-side performance a lot.

Happy reacting! I'm @tomas_brambora.