动态构建 RethinkDB 过滤器

Building RethinkDB filter dynamically

我想使用如下指定的过滤器过滤我的数据:

var filter = { minAge: 2, maxAge: 11, country:'uk', city':'london'};

在这种情况下,过滤将是:

r.db(dbName).table(tableName)
    .filter(r.row("minAge").ge(filter.minAge)
             .and(r.row("maxAge").le(filter.maxAge))
             .and(r.row('country').eq(filter.country))
             .and(r.row('city').eq(filter.city))
           );

然而,一些过滤谓词可能会丢失,例如,如果我只有最小年龄和城市,我只想对它们进行过滤:

var filter2 = { minAge: 2, city':'london'};

上面的过滤器应该得到下面的

r.db(dbName).table(tableName)
    .filter(r.row("minAge").ge(filter.minAge)             
             .and(r.row('city').eq(filter.city))
           );

如何根据可以传递给过滤函数的过滤对象键构建 ReQL 查询。

对不起,我理解错了,重新写下我的答案。

我认为你可以做的是编写一个通用函数,运行 在客户端 return 查询过滤器。

首先,如果您正在动态处理过滤器对象,则过滤器函数不知道应用哪个操作。鉴于此:

{city: 'London', minAge: 12}

对于城市,我们想要一个 eq,对于 minAge,我们想要一个 ge,但是由于我们是动态地这样做,所以最好为过滤器对象提出这样的语法:

{city: 'London', minAge: ['ge', 12]}

考虑到这一点,我提出了这个解决方案:

var filterObject = {
  minAge: ['ge', 12],
  city: 'london'
}

r.table('monitor').filter((function(filterObject) {
  var condition

  for (var key in filterObject) {
    var conditionForThisKey
    if (typeof key == 'string' || typeof key == 'number') {
      conditionForThisKey = r.row(key).eq(filterObject[key])
    } else {
      conditionForThisKey = r.row(key)[filterObject[key][0]](filterObject[key][1])
    }

    if (typeof condition === 'undefined') {
      condition = conditionForThisKey
    } else {
      condition = condition.and(conditionForThisKey)
    }
  }

  return condition
})(filterObject))
.run(connection)
.then(function(cursor){ //do stuff with result })
.error(function(err) { //err handling })

这样,我们就可以在客户端动态地为RethinkDB构建条件对象。 我认为我们可以使用 r.js 将该逻辑推送到 RethinkDB。但是我看不出在 RethinkDB 上让 运行 有什么意义,客户端有能力做到这一点。

如果有帮助请告诉我。

避免通过缺失字段进行过滤的一个有点肮脏的技巧是只添加默认值 -

r.db(dbName).table(tableName)
   .filter(r.row("minAge").default(filter.minAge).ge(filter.minAge)
      .and(r.row("maxAge").default(filter.maxAge).le(filter.maxAge))
      .and(r.row('country').default(filter.country).eq(filter.country))
      .and(r.row('city').default(filter.city).eq(filter.city))
   );

效率不高,不是很好,但如果您暂时不想过度设计它,它应该可以工作。

请注意,顺序扫描 - 在查询早期不使用限制的查询,或没有任何索引的查询,整体上只有 .filter() 函数 table - 将使用顺序索引,并且很慢。它不能很好地扩展。

如果有人正在寻找解决方案,这里是维护者 (srh) 提供的解决方案。

RethinkDB 查询只是对象,您可以创建通用函数来为您构建它们。

    function makeFilterExpr(x, obj) {
      let expr = r.expr(true);
      if ('minAge' in obj) { expr = expr.and(x('age').ge(obj['minAge'])); }
      if ('city' in obj) { expr = expr.and(x('city').eq(obj['city'])); }
      return expr;
    }
    
    // usage:
    let query = r.table('foo').filter(x => makeFilterExpr(x, {'minAge': 2, 'city': 'London'}));

您只需编写进行查询的代码。