2015-04-02 9 views
6

sto lavorando con una serie di dati che sembra qualcosa di simile:Come interrogare un indice più in RethinkDB su un array di oggetti

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

e ho voluto creare un indice secondario su bitrates, flettendo {multi:true} . Questo è stato il mio tentativo:

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

L'indice costruita bene, ma quando interrogo, niente ritorna - che sembra in contrasto con tutti gli esempi che ho letto qui:

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

La query ho scritto è questo:

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

non ci sono errori, a soli 0 risultati (e non ho circa 300 documenti con questi dati esatti).

Sto usando RethinkDB 2.0 RC1.

risposta

11

Quando si crea un indice per una colonna, i valori nella colonna vengono utilizzati letteralmente come le chiavi dell'indice. Nel tuo caso, i tasti per l'indice bitrates sarebbero gli oggetti all'interno della matrice bitrates nel documento.

Sembra che quello che vuoi sia un indice derivato dai valori in un campo del documento. Per fare ciò, si desidera definire una funzione di indicizzazione personalizzata che riduca il documento ai soli dati a cui tieni. Il modo più semplice per sperimentarli è iniziare scrivendo una query e, una volta soddisfatti dei risultati, convertirla in un'istruzione indexCreate().

Ecco una dichiarazione che afferra il vostro documento di esempio (con id 1), e pizzica le format e rate termini da tutti gli oggetti nella sua bitrate array, e poi li fonde insieme per creare una serie distinta di stringhe:

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

l'esecuzione di questa dichiarazione restituirà il seguente:

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

questo sembra buono, in modo che possiamo usare la nostra funzione per creare un indice. In questo caso, dal momento che ci aspettiamo la funzione di indicizzazione per restituire un insieme di elementi, anche noi vogliamo specificare {multi: true} per assicurarci di poter interrogare dai voci nel set, non è il set in sé:

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

Una volta creato, è possibile interrogare l'indice in questo modo:

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

È possibile anche fornire più termini di ricerca, in modo che corrisponda righe che corrispondono uno qualsiasi degli elementi:

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

Tuttavia, se un singolo documento corrisponde a più di un termine nella query, verrà restituito più di una volta.Per risolvere questo problema, aggiungere distinct():

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

Se necessario, si potrebbe anche considerare l'utilizzo di downcase() per normalizzare l'involucro dei termini utilizzati nella indice secondario.

Si potrebbe anche saltare tutte le attività di indicizzazione del tutto e utilizzare una query 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'); 
}) 

Detto questo, se si sta quasi sempre interrogare il vostro tavolo allo stesso modo, generando un indice secondario utilizzando un la funzione personalizzata si tradurrà in prestazioni notevolmente migliori.

+1

Grazie Nate - grande risposta! Penso che avrei dovuto aggiungere nella mia descrizione che il mio obiettivo era usare un multiindice su una serie di oggetti e suona come se ciò non fosse possibile con un up up '{multi: true}'. Questa è più di una cosa esplorativa che sto facendo - in entrambi i casi la tua risposta è stellare grazie :) –

0

Chiavi di indici secondari non possono essere oggetti in questo momento:

> 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 

È possibile tenere traccia di questo problema a https://github.com/rethinkdb/rethinkdb/issues/2773.

Per un work-around, si può fare questo:

> 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

Grazie ... user359whatever :). Come già detto sto usando 2.0 RC1, che non fa quello che stai suggerendo sopra - funziona perfettamente senza errori. –

+0

Rob - il tuo post ha detto 'r.db (" music "). Table (" catalog "). GetAll ([" mp3 "," 128K "], {index:" bitrate "})' non ha prodotto un errore, fa 'r.table ('foo'). getAll ({format:" mp3 ", rate:" 128K "}, {index: 'bitrates'})' non produce neanche un errore? – mlucy

Problemi correlati