在Ember中写一个Or过滤器

时间:2018-06-24 06:32:18

标签: javascript database ember.js ember-data

我想在Ember中编写一个raw-loader过滤器。我要实现的过滤器如下:

Or

我正在收集所有过滤器,然后在发送查询时将其传递:

(end_date <= filter_end_date && end_date >= filter_start_date) || (start_date >= filter_start_date && start_date <= filter_end_date) || (start_date <= filter_start_date && end_date >= filter_end_date)

查询如下:

filterOptions: [
    {
      name : 'state',
      op   : 'eq',
      val  : 'published'
    }
  ]

我浏览了文档,但没有找到任何东西。为该过滤器建模的最佳方法是什么?

2 个答案:

答案 0 :(得分:2)

您要的是REST API使用的过滤策略。这不是特定于ember.js。 store服务(您使用的query方法)由ember-data提供。 Ember-data是ember的默认持久层,默认情况下将ember-cli蓝图包含到新项目中。

默认情况下,余烬数据正在实现JSON API specification。该规范注册了filter查询参数以进行过滤,但是与所使用的过滤策略无关:

  

注意:JSON API与服务器支持的策略无关。过滤器查询参数可以用作许多过滤策略的基础。 (Source

只有一个过滤建议,该建议通过关联记录的ID解决过滤问题:

  

建议希望支持过滤   基于关联的资源收集通过允许查询来实现   将过滤器与关联名称结合在一起的参数。

     

例如,以下是对所有关联评论的请求   带有特定帖子:

     

GET / comments?filter [post] = 1 HTTP / 1.1

     

Source

嵌入到余烬数据中的唯一过滤策略是有关通过请求资源的多个ID进行过滤。如果使用内置JSONAPIAdapter且coalesceFindRequests optiontrue,则使用它。默认为false。在那种情况下,余烬数据将对一个资源的特定记录的多个请求合并到一个GET查询中,以避免触发多个查询。它使用filter查询参数以及方括号内的用于过滤(id)的属性和以逗号分隔的ID列表。例如。对/posts端点进行ID为1和2的帖子的查询将类似于:GET /posts?filter[id]=1,2

因此,将所有现有部分放在一起,仅涉及按(关联)资源的ID进行过滤。

有一个很好的理由说明JSON API规范对过滤策略不可知:一个非常合适的过滤策略是高度特定于应用程序的。在REST API上支持SQL的全部功能可能会给API带来严重的性能问题。

但是,有很多复杂的过滤策略,可以实施并完全符合JSON API中的建议以及ember-data的coalesceFindRequests功能。

例如,可以采用filtering syntax used by OpenStack。这样一来,就可以将由冒号分隔的运算符添加到过滤器中。通过该查询,请求所有2018年1月1日之后发布的帖子的查询将类似于:GET /posts?filter[published-at]=gt:2018-01-01。请注意,我还假设使用驼峰式字段名和ISO-8601日期字符串。但是,此语法不支持or运算符。对于不将or运算符的复杂性置于REST API过滤策略中,存在一些争论。通过使用分开的查询并合并返回的集合,您可以轻松地拥有该选项。

一种更复杂的过滤策略是Resource Query Language (RQL)。那是用等号将运算符和值分开。因此,上面示例中的请求看起来像:GET /posts?filter[published-at]=gt=2018-01-01 RQL还支持or运算符,使用圆括号将由竖线分隔的表达式分组。对在2018年1月1日之后但在2018年2月1日之前发布的帖子的查询看起来像是:GET /posts?(filter[published-at]=gt=2018-01-01|filter[published-at]=lt=2018-02-01)但是,有人可能会认为这不是查询参数的非常常用的语法,并且可能导致Web服务器,缓存,代理等问题。

由于ember-data通过data设置将store.query()的第二个参数直接传递给jQuery.ajax(),因此您完全可以根据应用程序的需求自由选择过滤策略。

答案 1 :(得分:0)

是的,@ jelhan是正确的。我们正在使用Flask-REST-JSONAPI作为过滤系统。过滤系统与ResourceList管理器使用的数据层完全相关。因此,我使用https://flask-rest-jsonapi.readthedocs.io/en/latest/filtering.html作为参考,并编写了如下的过滤器:

dateFilterWithEndDate: computed('start_date', 'end_date', function() {
    return EmberObject.create(
      {
        or:
          [
            {
              and: [
                {
                  name : 'starts-at',
                  op   : 'ge',
                  val  : this.get('start_date')
                },
                {
                  name : 'starts-at',
                  op   : 'le',
                  val  : this.get('end_date')
                }
              ]
            },
            {
              and: [
                {
                  name : 'ends-at',
                  op   : 'ge',
                  val  : this.get('start_date')
                },
                {
                  name : 'ends-at',
                  op   : 'le',
                  val  : this.get('end_date')
                }
              ]
            },
            {
              and: [
                {
                  name : 'starts-at',
                  op   : 'le',
                  val  : this.get('start_date')
                },
                {
                  name : 'ends-at',
                  op   : 'ge',
                  val  : this.get('end_date')
                }
              ]
            }
          ]
      }

    );
  }),

  dateFilterBasic: computed('start_date', function() {
    return EmberObject.create(
      {
        or: [
          {
            name : 'starts-at',
            op   : 'ge',
            val  : this.get('start_date')
          },
          {
            name : 'ends-at',
            op   : 'ge',
            val  : this.get('start_date')
          }
        ]
      }
    );
  }),

我将其添加到查询方法中的filter参数中,如下所示:

    if (endDate) {
      filterOptions.pushObject(this.get('dateFilterWithEndDate'));
    } else {
      filterOptions.pushObject(this.get('dateFilterBasic'));
    }

    return this.get('store').query('event', {
      sort   : 'starts-at',
      filter : filterOptions
    });