重新思考 |嵌套与链式查询,有什么区别吗?

rethinkdb | nested vs chained queries, any difference?

和chained有区别吗:

r.db('catbox').table("bw_mobile").filter(
    r.row("value")("appVersion")("major").le(2)
).filter(
  r.row("value")("appVersion")("minor").le(2)
).filter(
  r.row("value")("appVersion")("patch").le(10)
)

嵌套:

r.db('catbox').table("bw_mobile").filter(
      r.row("value")("appVersion")("major").le(2).and(
        r.row("value")("appVersion")("minor").le(2).and(
          r.row("value")("appVersion")("patch").le(10)
        )
      )
)

或 lambda 函数

r.db('catbox').table("bw_mobile").filter(
  r.js("(function (session) { 
        return session.value.appVersion.major < 0 
            || ( session.value.appVersion.major == 0 && session.value.appVersion.minor < 0 )
            || ( session.value.appVersion.major == 0 && session.value.appVersion.minor == 0 && session.value.appVersion.patch < 71 )
        ; 
    })")
)

太!

我认为第二种情况(单个 filter 和多个 and 表达式)效率最高,使用起来也最方便。 我会考虑以下想法:

r.filter,因为它是 documented总是 创建一个新的选择,一个流或一个数组,不管传递给 [ 的谓词函数的结果如何=13=]。 我不确定如何在 RethinkDB 中实现选择(我相信它们是 stream-like),但数组链接可能是分配中间数组的昂贵操作。 将此与 Array.prototype.filter 进行比较,后者创建一个新数组作为其结果。 流是惰性的,因此每个元素也被惰性地计算(或不计算),因此内存更小 foot-print。 将其与 iterators/streams 和其他语言的生成器进行比较(Iterator<E>/Stream<E> in Java,IEnumerator<T> and yield return in .NET/C #,JavaScript 中的迭代器和生成器函数,Python 中的 yield,shell 命令中的管道 | 等),您可以在其中组合 iterators/generators. 无论如何你都有中间过滤器。

单个表达式可以代替一堆链式过滤操作。 请注意表达式中的 r.and 运算有一个非常重要的特征:这是一个 short-circuit 求值运算。 如果 AND 运算的 left-hand 操作数是 false,则该运算甚至不需要计算 right-hand 表达式来获得始终为 false 的结果。 你不能用 r.filter 做这样的事情。 将此与每个查询可以指定一次的 SQL WHERE 子句进行比较(所有错误情况都可以被 AND 运算符简单地丢弃)。 此外,从实用的角度来看,您可以创建一个工厂方法,它可以有一个方便的名称和 returns 参数化 ReQL 表达式,甚至可以将其分配给常量,因为 ReQL 表达式是不可变的并且对 re-use 是安全的:

const maxVersionIs = (major, minor, patch) => r.row("value")("appVersion")("major").le(major)
    .and(r.row("value")("appVersion")("minor").le(minor))
    .and(r.row("value")("appVersion")("patch").le(patch));

const versionPriorToMilestone = maxVersionIs(2, 2, 10);

...

.filter(maxVersionIs(major, minor, patch))

...

.filter(versionPriorToMilestone)

ReQL 表达式 RethinkDB 查询实际上是表达式树,比执行 JavaScript 脚本更容易解析并直接转换为执行计划。 官方文档甚至 recommends 避免使用 r.js 以获得更好的性能。 我想这里的成本是 Java 脚本运行时设置、隔离脚本执行和检查脚本超时。 此外,脚本更多 error-prone,而表达式树可以在编译时或多或少地被检查。 但是,为了完整起见,即使有这些成本,r.js 也可以更强大,因为 ReQL 是一组有限的操作。 根据我的个人经验:我必须实现一种基于 RethinkDB 的 permission-checking 子系统,并且我需要在 RethinkDB 中进行按位与运算。 不幸的是,从 2.3 开始的 RethinkDB 不支持按位运算,所以我不得不使用 r.js: r.js('(function (user) { return !!(user.permissions & ${permissions}); })')。 RethinkDB 的未来版本将支持 bitwise operations,因此 r.getField('permissions').bitAnd(permissions)) 在未来的某一天应该可以更快地工作并且可以与其他表达式组合以适应单个 filter.

因为昨晚我运行遇到了类似的问题,这里没有很多RethinkDB的内容,所以我会分享我的解决方案。

export interface LooseObjectInterface {
  [key: string]: any;
};

const tldQuery: LooseObjectInterface = await r.table(tldDatabase)
  .orderBy({ index: r.asc("name") }) // alphabetical sort
  .filter((row: any) => {
    return row("collection")
      .contains(suppliedCollection[0])
      .or(row("collection").contains(suppliedCollection[1]))
      .or(row("collection").contains(suppliedCollection[2]))
      .or(row("collection").contains(suppliedCollection[3]))
      // ^ these extra "or"s silently fail, huzzah!
  })
  .pluck("name") // we just want the names
  .run(databaseConnection);

在我的代码中,suppliedCollection 是一个字符串数组。我的 table 中的每个项目都可以在 suppliedCollection 中包含任意数量的字符串,从一到四个。

根据一项集合中的这些字符串,我想找到包含这些相同字符串的其他项。

谢天谢地,如果 suppliedCollection[n]undefined,RethinkDB 会自动失败。