Il modo migliore per fare uno-a-molti “JOIN” in CouchDB

Sto cercando un CouchDB equivalente a “join SQL”.

Nel mio esempio ci sono documenti CouchDB che sono elementi di lista:

{ "type" : "el", "id" : "1", "content" : "first" } { "type" : "el", "id" : "2", "content" : "second" } { "type" : "el", "id" : "3", "content" : "third" } 

C’è un documento che definisce l’elenco:

 { "type" : "list", "elements" : ["2","1"] , "id" : "abc123" } 

Come puoi vedere il terzo elemento è stato cancellato, non fa più parte della lista. Quindi non deve essere parte del risultato. Ora voglio una vista che restituisca gli elementi di contenuto incluso l’ordine corretto.

Il risultato potrebbe essere:

 { "content" : ["second", "first"] } 

In questo caso l’ordine degli elementi è già come dovrebbe essere. Un altro ansible risultato:

 { "content" : [{"content" : "first", "order" : 2},{"content" : "second", "order" : 1}] } 

Ho iniziato a scrivere la funzione mappa:

 map = function (doc) { if (doc.type === 'el') { emit(doc.id, {"content" : doc.content}); //emit the id and the content exit; } if (doc.type === 'list') { for ( var i=0, l=doc.elements.length; i<l; ++i ){ emit(doc.elements[i], { "order" : i }); //emit the id and the order } } } 

Questo è il massimo che posso ottenere. Puoi correggere i miei errori e scrivere una funzione di riduzione? Ricorda che il terzo documento non deve essere parte del risultato.

Naturalmente puoi anche scrivere una diversa funzione di mappa. Ma la struttura dei documenti (un documento di elemento definitivo e un documento di entrata per ogni voce) non può essere modificata.


EDIT: non perdere il commento di JasonSmith alla sua risposta, dove descrive come farlo più breve.

Grazie! Questo è un ottimo esempio per mostrare le nuove funzionalità di CouchDB 0.11 !

È necessario utilizzare la funzionalità relativa al recupero dei dati per fare riferimento ai documenti nella vista. Facoltativamente, per un JSON più conveniente, utilizzare una funzione _list per pulire i risultati. Vedi l’ articolo di Couchio su “JOIN” per i dettagli.

Ecco il piano:

  1. In primo luogo, hai un contstraint univoco sui tuoi documenti. Se due di loro hanno id = 2, questo è un problema. È necessario utilizzare invece il campo _id se id . CouchDB garantisce l’unicità, ma anche il resto di questo piano richiede _id per recuperare i documenti per ID.

     { "type" : "el", "_id" : "1", "content" : "first" } { "type" : "el", "_id" : "2", "content" : "second" } { "type" : "el", "_id" : "3", "content" : "third" } 

    Se la modifica dei documenti per utilizzare _id è assolutamente imansible, è ansible creare una vista semplice per emit(doc.id, doc) e quindi reinserirla in un database temporaneo. Questo converte id in _id ma aggiunge una certa complessità.

  2. La vista emette {"_id": content_id} dati digitati su [list_id, sort_number] , per “raggruppare” le liste con il loro contenuto.

     function(doc) { if(doc.type == 'list') { for (var i in doc.elements) { // Link to the el document's id. var id = doc.elements[i]; emit([doc.id, i], {'_id': id}); } } } 

    Ora c’è una semplice lista di documenti el , nell’ordine corretto. Puoi usare startkey e endkey se vuoi vedere solo un particolare elenco.

     curl localhost:5984/x/_design/myapp/_view/els {"total_rows":2,"offset":0,"rows":[ {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","0"],"value":{"_id":"2"}}, {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","1"],"value":{"_id":"1"}} ]} 
  3. Per ottenere il contenuto el , include_docs=true query con include_docs=true . Attraverso la magia di _id , i documenti el caricheranno.

     curl localhost:5984/x/_design/myapp/_view/els?include_docs=true {"total_rows":2,"offset":0,"rows":[ {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","0"],"value":{"_id":"2"},"doc":{"_id":"2","_rev":"1-4530dc6946d78f1e97f56568de5a85d9","type":"el","content":"second"}}, {"id":"036f3614aeee05344cdfb66fa1002db6","key":["abc123","1"],"value":{"_id":"1"},"doc":{"_id":"1","_rev":"1-852badd683f22ad4705ed9fcdea5b814","type":"el","content":"first"}} ]} 

    Nota, questa è già tutte le informazioni di cui hai bisogno. Se il tuo cliente è flessibile, puoi analizzare le informazioni da questo JSON. Il prossimo passo opzionale semplicemente lo riformatta per abbinare ciò che ti serve.

  4. Utilizzare una funzione _list , che semplicemente riformatta l’output della vista. Le persone li usano per l’output di XML o HTML, tuttavia renderemo il JSON più conveniente.

     function(head, req) { var headers = {'Content-Type': 'application/json'}; var result; if(req.query.include_docs != 'true') { start({'code': 400, headers: headers}); result = {'error': 'I require include_docs=true'}; } else { start({'headers': headers}); result = {'content': []}; while(row = getRow()) { result.content.push(row.doc.content); } } send(JSON.stringify(result)); } 

    I risultati corrispondono. Naturalmente nella produzione avrete bisogno di startkey e endkey per specificare l’elenco che volete.

     curl -g 'localhost:5984/x/_design/myapp/_list/pretty/els?include_docs=true&startkey=["abc123",""]&endkey=["abc123",{}]' {"content":["second","first"]}