Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic Properties or Aggregate Functions in Loopback Models

How would I go about using aggregate functions in Loopback models? If I have a model backed by a mysql database, could I have Model1 with a hasMany relation to Model2 (with a given numeric property), and have a property in Model1 that grabs the SUM of that field from Model2?


    {
        "Model1" : {
            "Relations" : {
                "model2s" : {
                    "type": "hasMany",
                    "model": "Model2",
                    "foreignKey": "model1Id"
                }
            },
            "Properties" : {
                "total" : {
                    "type": "Number"
                    [SUM of Model2 'amount' field]
                }
            }
        },
        "Model2" : {
            "Relations" : {
                "model1s" : {
                    "type": "belongsTo",
                    "model": "Model1",
                    "foreignKey": "model1Id"
                }
            },
            "Properties" : {
                "amount" : {
                    "type": "Number"
                }
            }
        }
    }

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 want to return a value from a relation if it exists, otherwise return the one that exists on the primary model.

I have tried this (pseudocode):


    module.exports = function(MyModel) {
        MyModel.on('attached', function() {
            var app = MyModel.app;

            MyModel.getter['total'] = function() {
                return (this.model1Id ? this.model1.total : this.total);
            };
        });

    };

However, I end up getting a RangeError: Maximum call stack size exceeded error (similar to what is noted in this question). I'm assuming that is because it recursively calls the getter over and over, but I'm not sure of the way to resolve the issue.

Thanks in advance...

like image 304
jcq Avatar asked Aug 22 '14 02:08

jcq


1 Answers

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();
  }
});
like image 131
cloudlena Avatar answered Oct 16 '22 17:10

cloudlena