【问题标题】:How to query a multi index in RethinkDB over an array of objects如何在 RethinkDB 中通过对象数组查询多索引
【发布时间】:2015-04-02 14:18:06
【问题描述】:

我正在使用如下所示的数据集:

"bitrates": [
  {
    "format":  "mp3" ,
    "rate":  "128K"
  } ,
  {
    "format":  "aac" ,
    "rate":  "192K"
  }
] ,
"details": [ ... ] ,
"id": 1 ,
"name":  "For Those About To Rock We Salute You" ,
"price": 1026 ,
"requires_shipping": false ,
"sku":  "ALBUM-1" 
}

我想在bitrates 上创建一个二级索引,弯曲{multi:true}。这是我的尝试:

r.db("music").table("catalog").indexCreate("bitrates", {multi: true})

索引构建得很好,但是当我查询它时,什么都没有返回——这似乎与我在这里阅读的每个示例相反:

http://rethinkdb.com/docs/secondary-indexes/javascript/

我写的查询是这样的:

r.db("music").table("catalog").getAll(["mp3", "128K"], {index : "bitrates"})

没有错误,只有 0 个结果(我有大约 300 个包含这些确切数据的文档)。

我正在使用 RethinkDB 2.0 RC1。

【问题讨论】:

    标签: rethinkdb


    【解决方案1】:

    当您为列创建索引时,列中的值按字面意思用作索引的键。在您的情况下,您的 bitrates 索引的键将是文档中 bitrates 数组中的对象。

    您想要的似乎是从文档字段中的值派生的索引。为此,您需要定义一个自定义索引函数,将文档缩减为您关心的数据。试验它们的最简单方法是先编写一个查询,一旦您对结果感到满意,就将其转换为 indexCreate() 语句。

    这是一个语句,它获取您的示例文档(id 为 1),并从其 bitrate 数组中的所有对象中提取 formatrate 术语,然后将它们合并在一起以创建一个不同的集合字符串:

    r.db('music').table('catalog').get(1).do(function(row) {
      return row('bitrates').map(function(bitrate) {
        return [bitrate('format'), bitrate('rate')];
      }).reduce(function(left, right) {
        return left.setUnion(right);
      })
    })
    

    运行此语句将返回以下内容:

    ["mp3", "128K", "aac", "192K"]
    

    这看起来不错,所以我们可以使用我们的函数来创建索引。在这种情况下,由于我们期望索引函数返回一组项目,我们还希望指定 {multi: true} 以确保我们可以通过集合中的 items 而不是集合本身进行查询:

    r.db('music').table('catalog').indexCreate('bitrates', function(row) {
      return row('bitrates').map(function(bitrate) {
        return [bitrate('format'), bitrate('rate')];
      }).reduce(function(left, right) {
        return left.setUnion(right);
      })
    }, {multi: true})
    

    创建后,您可以像这样查询索引:

    r.db('music').table('catalog').getAll('mp3', {index: 'bitrates'})
    

    您还可以提供多个查询词,以匹配与任何项目匹配的行:

    r.db('music').table('catalog').getAll('mp3', '128K', {index: 'bitrates'})
    

    但是,如果单个文档与您的查询中的多个词匹配,它将被多次返回。要解决此问题,请添加 distinct():

    r.db('music').table('catalog').getAll('mp3', '128K', {index: 'bitrates'}).distinct()
    

    如有必要,您还可以考虑使用downcase() 来规范二级索引中使用的术语的大小写。

    您也可以完全跳过所有索引业务并使用filter() 查询:

    r.db('music').table('catalog').filter(function(row) {
      return row('bitrates').map(function(bitrates) {
        return [bitrates('format'), bitrates('rate')];
      }).reduce(function(left, right) {
        return left.setUnion(right);
      }).contains('mp3');
    })
    

    也就是说,如果您几乎总是以相同的方式查询表,那么使用自定义函数生成二级索引会显着提高性能。

    【讨论】:

    • 感谢 Nate - 很好的回答!我想我应该在我的描述中添加我的目标是在对象数组上使用多索引,这听起来像直接向上 {multi:true} 是不可能的。这更像是我正在做的一件探索性的事情——无论哪种方式,你的回答都很出色,谢谢:)
    【解决方案2】:

    二级索引的键现在不能是对象:

    > r.table('foo').indexCreate('bitrates', {multi: true})
    > r.table('foo').getAll({format: "mp3", rate: "128K"}, {index: 'bitrates'})
    RqlRuntimeError: Secondary keys must be a number, string, bool, pseudotype, or array
    

    您可以通过 https://github.com/rethinkdb/rethinkdb/issues/2773 跟踪此问题。

    对于解决方法,您可以这样做:

    > r.table('foo').indexCreate('bitrates', function(row){
        return row('bitrates').map(function(bitrate){return bitrate.coerceTo('array');})
      }, {multi: true});
    > r.table('foo').getAll(r.expr({format: "mp3", rate: "128K"}).coerceTo('array'), {index: 'bitrates'})
    

    【讨论】:

    • 谢谢... user359whatever :)。如前所述,我使用的是 2.0 RC1,它并没有按照您上面的建议执行 - 它工作得很好,没有错误。
    • Rob -- 你的帖子说r.db("music").table("catalog").getAll(["mp3", "128K"], {index : "bitrates"}) 没有产生错误,r.table('foo').getAll({format: "mp3", rate: "128K"}, {index: 'bitrates'}) 也没有产生错误吗?
    猜你喜欢
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多