动态构建 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'}));
您只需编写进行查询的代码。
我想使用如下指定的过滤器过滤我的数据:
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'}));
您只需编写进行查询的代码。