2015-04-02 18 views
6

我使用的數據集,看起來像這樣的工作查詢多指數:如何RethinkDB在對象的數組

"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。

回答

11

爲列創建索引時,列中的值實際上用作索引的鍵。在你的情況下,bitrates索引的鍵將是文檔中bitrates數組內的對象。

它看起來像你想要的是從文檔的字段中的值派生的索引。爲此,您需要定義一個自定義索引函數,將文檔簡化爲您關心的數據。實驗最簡單的方法是先寫一個查詢,一旦對結果感到滿意,將其轉換爲indexCreate()聲明。

下面是抓住你的樣本文件(ID:1)的聲明,並拽着從所有對象的formatrate方面在其bitrate數組,然後將它們合併起來以創建一組不同的字符串:

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},以確保我們可以通過項目在集查詢,而不是集本身:

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

這就是說,如果你總是查詢您的表以同樣的方式,使用生成輔助索引自定義功能將會顯着提高性能。二級指標的

+1

由於內特 - 偉大的答案!我認爲我應該在我的描述中加入我的目標是在一個對象數組上使用多重索引,並且聽起來像用'{multi:true}'不可能。這是我正在做的更多探索性的事情 - 無論哪種方式,你的答案是恆星謝謝:) – 2015-04-02 15:49:04

0

關鍵字不得對象現在:

> 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'}) 
+0

謝謝... user359whatever :)。正如前面提到的,我使用的是2.0 RC1,它不符合上面的建議 - 它工作得很好,沒有錯誤。 – 2015-04-02 19:52:46

+0

Rob - 你的文章說r.db(「music」).table(「catalog」).getAll([「mp3」,「128K」],{index:「bitrates」})'沒有生成錯誤,是否'r.table('foo')。getAll({format:「mp3」,rate:「128K」},{index:'bitrates'})'也不會產生錯誤? – mlucy 2015-04-03 23:41:29

相關問題