【问题标题】:rethinkdb | nested vs chained queries, any difference?重新思考数据库 |嵌套查询和链式查询,有什么区别吗?
【发布时间】:2018-03-15 18:53:04
【问题描述】:

链式有什么区别:

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 )
        ; 
    })")
)

TY!

【问题讨论】:

    标签: rethinkdb rethinkdb-javascript


    【解决方案1】:

    我相信第二种情况(单个filter 和多个and 表达式)是最有效和最方便使用的。 我会考虑以下想法:

    r.filter,因为它是documented总是会创建一个新的选择、一个流或一个数组,而不管传递给r.filter 的谓词函数的结果如何。 我不确定如何在 RethinkDB 中实现选择(我相信它们类似于流),但数组链接可能是分配中间数组的昂贵操作。 将此与 Array.prototype.filter 进行比较,后者会创建一个新数组作为其结果。 流是惰性的,因此每个元素也是惰性计算(或不计算)的,因此内存占用量更小。 将此与其他语言中的迭代器/流和生成器进行比较(Java 中的Iterator&lt;E&gt;/Stream&lt;E&gt;,.NET/C# 中的IEnumerator&lt;T&gt;yield return,JavaScript 中的迭代器和生成器函数,Python 中的yield,管道@ 987654334@ 在 shell 命令等中),您可以在其中组合迭代器/生成器。 无论如何,您都有中间过滤器。

    单个表达式可以替换一堆链式过滤操作。 请注意,表达式中的 r.and 操作有一个非常重要的特性:这是一种短路评估操作。 如果 AND 操作的左侧操作数是 false,则该操作甚至不需要计算右侧表达式即可得到始终为 false 的结果。 你不能用r.filter 做这样的事情。 将此与可以在每个查询中指定一次的 SQL WHERE 子句进行比较(AND 运算符可以简单地丢弃所有错误情况)。 此外,从实用的角度来看,您可以创建一个工厂方法,该方法可以具有方便的名称并返回参数化的 ReQL 表达式,甚至可以将其分配给常量,因为 ReQL 表达式是不可变的并且可以安全地重用:

    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 以获得更好的性能。 我猜这里的成本是 JavaScript 运行时设置、隔离脚本执行和检查脚本超时。 此外,脚本更容易出错,而在编译期间可以或多或少地检查表达式树。 但是,为了完整起见,r.js 即使有这些成本也可以更强大,因为 ReQL 是一组有限的操作。 根据我的个人经验:我必须实现一种基于 RethinkDB 的权限检查子系统,并且我需要在 RethinkDB 中进行按位与运算。 不幸的是,RethinkDB 2.3 不支持按位运算,所以我不得不使用r.js:r.js('(function (user) { return !!(user.permissions &amp; ${permissions}); })')。 RethinkDB 的未来版本将支持bitwise operations,因此r.getField('permissions').bitAnd(permissions)) 应该在未来的某一天更快地工作,并且可以与其他表达式组合以适应单个filter

    【讨论】:

      【解决方案2】:

      因为我昨晚遇到了类似的问题,而且这里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 是一个字符串数组。我表中的每个项目都可以在 suppliedCollection 中包含任意数量的字符串,从 1 到 4。

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-15
        相关资源
        最近更新 更多