Dynamic Properties or Aggregate Functions in Loopback Models

This can be done with Loopback's operational hooks.

Model1.observe('loaded', function (ctx, next) {
  if (ctx.instance) {
    var sum = 0;

    Model1.app.models.Model2.find({
      where: {
        model1Id: ctx.instance.id
      },
      fields: {
        givenNumericProperty: true
      }
    }, function (err, model2s) {
      if (err) return next(err);

      if (model2s.length) {
        model2s.forEach(function (model2) {
          sum += model2.givenNumericProperty;
        });

        ctx.instance.calculatedProperty = sum;
      }

      return next();
    });

  } else {
    return next();
  }
});

AFAIK loopback does not support aggregate functions/properties at the moment. Please open a github issue to track this as a feature request.

Note that accessing data of related models is an asynchronous operation, thus it's not possible to reliably implement a property (a getter function) to return the aggregated result.

Here is a mock-up showing how to correctly implementat a computed total:

MyModel.prototype.getTotal = function(cb) {
  if (!this.model1Id) {
    // No related model, return the total from this model.
    return cb(null, this.total);
  }

  // Fetch the related model and return its total
  this.model1(function(err, model1) {
    if (err)
      cb(err);
    else
      cb(null, model1.total);
  });
}

On a separate matter, what is the correct way to put a conditional in a model, so that the value returned by a getter depends on some expression? I end up getting a RangeError: Maximum call stack size exceeded error

As I explained in the answer you have linked to, this.total calls your custom getter function, which in turns calls this.total and so on.

The solution is to read the value from the internal data object:

MyModel.getter['total'] = function() {
   return this.__data.total;
};

You can try 3rd party plugins:

1) Loopback connector for aggregation: https://github.com/benkroeger/loopback-connector-aggregate

2) Loopback mixins for computed/calculated properties (works only when new model instance created): https://github.com/fullcube/loopback-ds-calculated-mixin https://github.com/fullcube/loopback-ds-computed-mixin

3) Loopback mixin for change tracking (launches on every update): https://github.com/fullcube/loopback-ds-changed-mixin

4) If you need a stats - here is another mixin: https://github.com/jonathan-casarrubias/loopback-stats-mixin

5) You can count related models: https://github.com/exromany/loopback-counts-mixin

6) You can automaticly denormalize and save related data and choose what fields will be stored (useful for caching): https://github.com/jbmarchetti/loopback-denormalize

7) If you need a computed properties for field mapping during import: https://github.com/jonathan-casarrubias/loopback-import-mixin