【问题标题】:Dynamic Properties or Aggregate Functions in Loopback Models环回模型中的动态属性或聚合函数
【发布时间】:2014-10-15 19:33:09
【问题描述】:

如何在 Loopback 模型中使用聚合函数?如果我有一个由 mysql 数据库支持的模型,我是否可以让 Model1 与 Model2 具有 hasMany 关系(具有给定的数字属性),并且在 Model1 中有一个属性可以从 Model2 中获取该字段的 SUM?

{ “模型1”:{ “关系”:{ “模型2s”:{ "type": "hasMany", “模型”:“模型 2”, "foreignKey": "model1Id" } }, “特性” : { “全部的” : { “类型”:“数字” [Model2‘金额’字段的总和] } } }, “模型2”:{ “关系”:{ “模型1s”:{ “类型”:“属于”, “模型”:“模型 1”, "foreignKey": "model1Id" } }, “特性” : { “数量” : { “类型”:“数字” } } } }

另外,在模型中放置条件的正确方法是什么,以便 getter 返回的值取决于某个表达式?我想从关系中返回一个值(如果存在),否则返回主模型上存在的值。

我试过这个(伪代码):

module.exports = 功能(MyModel){ MyModel.on('附加', function() { var app = MyModel.app; MyModel.getter['total'] = function() { 返回(this.model1Id?this.model1.total:this.total); }; }); };

但是,我最终得到了一个RangeError: Maximum call stack size exceeded 错误(类似于this question 中提到的内容)。我假设这是因为它一遍又一遍地递归调用 getter,但我不确定解决问题的方法。

提前谢谢...

【问题讨论】:

    标签: strongloop loopbackjs


    【解决方案1】:

    这可以通过 Loopback 的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();
      }
    });
    

    【讨论】:

    • 哦,将它放在“已加载”挂钩上是个好主意。我得试一试。谢谢!
    • 这在没有聚合的情况下也可以正常工作,只需添加简单的动态属性。我用它来添加一个通过 REST 公开的动态属性,该属性根据 dateModified 属性计算新近属性。
    • 我也使用“加载”来添加计算属性,但缺点是您无法按这些计算属性进行过滤。我们有一组具有“deletedAt”属性的对象,该属性包含项目被删除的日期。我添加了一个名为“deleted”的动态属性,它是真实的“deletedAt”属性存在并且不是假的。不幸的是,我无法过滤“已删除”属性。
    • 有没有办法添加动态属性并在其上使用过滤器?
    • 是的,需要动态过滤器吧
    【解决方案2】:

    AFAIK 环回目前不支持聚合函数/属性。请open a github issue将此作为功能请求进行跟踪。

    请注意,访问相关模型的数据是异步操作,因此无法可靠地实现属性(getter 函数)来返回聚合结果。

    这是一个模型,展示了如何正确实现计算出的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);
      });
    }
    

    另外,在模型中放置条件的正确方法是什么,以便 getter 返回的值取决于某个表达式? 我最终得到一个RangeError: Maximum call stack size exceeded 错误

    正如我在您链接到的答案中解释的那样,this.total 调用您的自定义 getter 函数,该函数又调用 this.total 等等。

    解决方法是从内部数据对象中读取值:

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

    【讨论】:

    • 我似乎在this.__data 中看不到任何东西——如果我向控制台吐出this,我看不到这样的键。我是在错误的范围内使用它还是什么?我正在上面列出的上下文中执行此操作(只需将 getter 函数中的内容替换为对 this.__data 的调用,如您所示);这不正确吗?
    • 注意:it is possible to implement an asynchronous getter function 按照 OP 的要求。但是,Loopback 不支持这样的功能 OOTB。
    【解决方案3】:

    您可以尝试 3rd 方插件:

    1) 用于聚合的环回连接器: https://github.com/benkroeger/loopback-connector-aggregate

    2) 用于计算/计算属性的 Loopback mixin(仅在创建新模型实例时有效): https://github.com/fullcube/loopback-ds-calculated-mixin https://github.com/fullcube/loopback-ds-computed-mixin

    3) 用于更改跟踪的 Loopback mixin(在每次更新时启动): https://github.com/fullcube/loopback-ds-changed-mixin

    4) 如果您需要统计信息 - 这是另一个 mixin: https://github.com/jonathan-casarrubias/loopback-stats-mixin

    5) 可以统计相关模型: https://github.com/exromany/loopback-counts-mixin

    6)您可以自动反规范化和保存相关数据,并选择将存储哪些字段(用于缓存): https://github.com/jbmarchetti/loopback-denormalize

    7) 如果您需要在导入期间为字段映射计算属性: https://github.com/jonathan-casarrubias/loopback-import-mixin

    【讨论】:

    • 第一个似乎已被私有化
    【解决方案4】:

    我不确定你是否找到了你要找的东西,但我正在寻找类似的功能但找不到。在询问堆栈溢出后,I wound up writing my own plugin,在那个链接中有详细说明。

    【讨论】:

      【解决方案5】:

      使用 loopback 3 你可以这样做:

        Report.observe("loaded", (ctx, next) => {  
          ctx.data.SOMEKEY = 'SOME VALUE'
          next();
      

      });

      【讨论】:

        猜你喜欢
        • 2023-01-08
        • 2019-02-11
        • 2011-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多