如何在 rethinkdb 中使用另一个查询的结果进行插入?

How to insert using the result of another query in rethinkdb?

使用 rethinkdb 数据浏览器

r.db('exports').table('requests') 

获取

{
  "options": {
    "params": {
      "foo": "bof"
      "sort": "desc",
      "page": 6
    }
  } ,
  "url": "https://url1.tld/"
} 

{
  "options": {
    "auth": {
      "type":  "basic" ,
      "pass":  "dnkykngcntry1" ,
      "user":  "diddy"
    } ,
    "params": {
      "foo": "bar"
      "sort": "asc",
      "page": 3
    }
  } ,
  "url": "https://url2.test/"
} 

...

现在我想这样做

r.db('exports').table('responses').insert(
  r.db('exports').table('requests').map(req => ({
    requestId: req('id'),
    requestedAt: r.now(),
    response: r.http(req('url'), req('options'))
  }))
)

出现此错误:

e: Expected 1 argument (not including options) but found 2.

如果我使用 request 文档之一的值调用 r.http 函数,一切正常

// http command syntax
// r.http(url[, options]) → value
// r.http(url[, options]) → stream

r.http("https://url1.tld/", {
    "params": {
      "foo": "bof"
      "sort": "desc",
      "page": 6
    }
  })
// <response text>

为什么它不能与循环中的 req('url')req('options') 一起使用?

我不是 RethinkDB 专家,但我可能可以对问题做一个简单浅显的 analysis/fix(假设您正在使用 JavaScript)。

Why doesn't it work with req('url') and req('options') in the loop then?

我认为这不是与循环相关的问题,更有可能是 RethinkDB 处理 ReQL 表达式和可能的可选参数(如果考虑到错误消息)的方式。 req('url')req('options') 都是 ReQL 表达式,可以使用 r.expr(...).

手动实例化

同时考虑以下与您的问题相关的代码:

// These two are your req('url') and req('options') equivalents respectively
const url = r.expr('https://postman-echo.com/get');
const options = r.expr({ params: { foo: 1, bar: 2 } });
// ...
r.http(url, options);

e: Expected 1 argument (not including options) but found 2.

好吧,让我们尝试使用简单的 r.http(url) 在没有 options 参数的情况下 运行 它,这就是它得到的结果:

{
    "args": { },
    "headers": {
        "accept": "*/*",
        "accept-encoding": "deflate, gzip",
        "host": "postman-echo.com",
        "user-agent": "RethinkDB/2.3.2-windows-beta-472-ga2117b",
        "x-forwarded-port": "443",
        "x-forwarded-proto": "https"
    } ,
    "url": "https://postman-echo.com/get"
}

我相信 r.expr(...)-实例化的 ReQL 值与 options 在 is-this-options 检测时发生冲突(可能是由于 undefined 引起的相同行为)。 您所要做的就是将您的文档属性包装在一个原始 JavaScript 对象中,因为 RethinkDB 似乎可以完美地处理嵌套属性。

r.http(url, rebuildOptions(options));

其中由于 r.http() API 限制,rebuildOptions 可以实现为相当有限的功能,例如:

const rebuildOptions = options => ({
    method: options('method').default('GET'), // default GET is fine for method
    // auth: don't know how to deal with auth - we cannot assign undefined to the property and cannot provide the default auth too
    params: options('params').default({}), // default {} is fine for params
    header: options('header').default({}), // the headers will be merged in the final request
    // data: don't know how to deal with data too - we can analyze options('method'), but cannot assign a good default value
});

又脏又弱。 我还可以建议我在检查 ReQL 值结构时发现的更 "hackish" 和更通用的实现:

// This looks to work with any ReQL values
const unexpr = expr => Object.assign({}, expr.optargs);
r.http(url, unexpr(options));

现在两种实现都可以 return:

{
    "args": {
        "bar": "2",
        "foo": "1"
    } ,
    "headers": {
        "accept": "*/*",
        "accept-encoding": "deflate, gzip",
        "host": "postman-echo.com",
        "user-agent": "RethinkDB/2.3.2-windows-beta-472-ga2117b",
        "x-forwarded-port": "443",
        "x-forwarded-proto": "https"
    } ,
    "url": "https://postman-echo.com/get?bar=2&foo=1"
}

它看起来像是一个设计缺陷(r.expr() 没有它的 "unwrapper" 对应物,如果 RethinkDB 需要的话)或者一个可选的参数检测错误,可能值得提交给 RethinkDB issue tracker 至少得到 RethinkDB 团队的反馈。

请记住,您正在构造一个要发送到服务器的查询,上面描述的函数 rebuildOptions 从 "options" 表达式构造一个表达式。这可能会导致服务器在三个不同的地方重新计算 options 表达式。 (在实践中,这确实会发生。)对于查询构造辅助函数,最好使用 r.do 构造查询以避免重新评估参数表达式,如果表达式在较大的围绕它构建的表达式。

const rebuildOptions = options => options.do(x => ({
    method: x('method').default('GET'),
    params: x('params').default({}),
    header: x('header').default({}),
}));

正如我在 Github 问题中提到的那样,这是一个有意的设计决定。必须提供函数的可选参数 "statically," 并且不同语言的不同客户端驱动程序可能无法使用单个字典表示可选参数。