为什么LoopBack中的这个嵌套关系会返回重复的结果?

时间:2017-02-01 21:56:44

标签: loopbackjs

当我查询包含嵌套模型时 - 例如GET /api/Widgets/1?filter={include: {"foos": "bars"}} - 我的结果中出现重复的foos。我认为这是由于LEFT JOIN或类似的东西,因为我正在使用MySQL,但是当我在loopback:connector:mysql调试模式下运行LoopBack时,我可以看到初始小部件的查询运行一次,但foo的查询运行两次,bar的查询运行两次。为什么会出现这种情况,我可以改变什么(我的模型,我的代码或我的期望)?

型号:

{
  "name": "Widget",
  ...
  "relations": {
    "foos": {
      "type": "hasMany",
      "model": "Foo",
      "foreignKey": "widgetId"
    }
  }
}

{
  "name": "Foo",
  ...
  "relations": {
    "bars": {
      "type": "hasMany",
      "model": "Bar",
      "foreignKey": "fooId"
    },
    "widget": {
      "type": "belongsTo",
      "model": "Widget",
      "foreignKey": ""
    }
  }
}

{
  "name": "Bar"
  ...
  "relations": {
    "foo": {
      "type": "belongsTo",
      "model": "Foo",
      "foreignKey": ""
    }
  }
}

结果:

{
  id: 1
  foos: [
    {
      id: 2,
      bars: [
        {
          id: 3
        }
      ]
    },
    {
      id: 2,
      bars: [
        {
          id: 3
        }
      ]
    }
  ]
}

期待:

{
  id: 1
  foos: [
    {
      id: 2,
      bars: [
        {
          id: 3
        }
      ]
    }
  ]
}

这是我认为正在为此请求运行的释义SQL:

SELECT `...` FROM `Widget` WHERE `id`=1 ORDER BY `id` LIMIT 1
SELECT `...` FROM `Foo` WHERE `widget_id` IN (1) ORDER BY `id`
SELECT `...` FROM `Foo` WHERE `widget_id` IN (1) ORDER BY `id`
SELECT `...` FROM `Bar` WHERE `foo_id` IN (2) ORDER BY `id`
SELECT `...` FROM `Bar` WHERE `foo_id` IN (2) ORDER BY `id`

我正在使用Loopback 3.x。

更新:GET /api/Widgets/1?filter={include: {"foos": "bars"}}的请求出现此行为时,Widgets.findById(id, {include: {"foos": "bars"}})的服务器端执行效果很好。所以,目前我将创建一个远程方法来执行此操作,并可能使用LoopBack提交错误报告。

2 个答案:

答案 0 :(得分:2)

我使用的是this mixin,它将查询的limit限制为最大值。如果查询中存在include,则mixin还会对包含范围设置限制,如下所示:

"include": {"foo":"bar","scope":{"limit":1}}

似乎mixin假设所有包含的对象都将以{"relation":"foo", "scope":{"include:"bars"}}的形式编写,因此包含会被添加两次。

为了它的价值,我写了这个简单的mixin来限制最大结果数,除非使用上面链接的那个指定和停止:

<强>公共/模型/ model.json:

"mixins": {
    "ResultsetLimit": {
        "limit": 100
    }
}

<强>公共/混入/结果集-limit.js:

const _ = require('lodash');

module.exports = (Model, options) => {

    /**
     * Modify incoming query to apply appropriate limit filters.
     */
    Model.beforeRemote('**', (ctx, unused, next) => {

        // Get the limit from the request, defaulting to the max limit.
        const request_limit = _.toNumber(_.get(ctx, 'args.filter.limit', options.limit));

        // Set the limit.
        _.set(ctx, 'args.filter.limit', request_limit);

        next();

    });

};

答案 1 :(得分:1)

您是否尝试删除以下行? 因为默认情况下,如果未设置foreignKey,则会将其设置为<relationName>Id。但是,由于您将其设置为空白,因此环回不会查找要引用的任何列。因此它会获得相关模型的所有记录。

{
  "name": "Widget",
  ...
  "relations": {
    "foos": {
      "type": "hasMany",
      "model": "Foo",
      "foreignKey": "widgetId"
    }
  }
}

{
  "name": "Foo",
  ...
  "relations": {
    "bars": {
      "type": "hasMany",
      "model": "Bar",
      "foreignKey": "fooId"
    },
    "widget": {
      "type": "belongsTo",
      "model": "Widget",
      "foreignKey": "" // remove this
    }
  }
}

{
  "name": "Bar"
  ...
  "relations": {
    "foo": {
      "type": "belongsTo",
      "model": "Foo",
      "foreignKey": "" //remove this
    }
  }
}

更新:

这就是我称之为第二级(或第三级)的关系:

/api/Widgets/1?filter={include: [{"relation":"foo", "scope":{"include:"bars"}}]}