2010-06-13 4 views
32

Ich bin auf der Suche nach einem CouchDB-Äquivalent zu "SQL Joins".Die beste Möglichkeit, One-to-Many "JOIN" in CouchDB zu machen

In meinem Beispiel gibt es CouchDB Dokumente, Listenelemente sind:

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

Es ist ein Dokument, das die Liste definiert:

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

Wie Sie das dritte Element wurde gelöscht sehen kann, ist es ist nicht mehr Teil der Liste. Also muss es nicht Teil des Ergebnisses sein. Jetzt möchte ich eine Ansicht, die die Inhaltselemente einschließlich der richtigen Reihenfolge zurückgibt.

könnte das Ergebnis sein:

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

In diesem Fall wird die Reihenfolge der Elemente bereits ist, wie es sein sollte. Ein weiteres mögliches Ergebnis:

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

Ich begann die Karte Funktion zu schreiben:

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

Dies ist so weit wie ich bekommen kann. Kannst du meine Fehler korrigieren und eine Reduce-Funktion schreiben? Denken Sie daran, dass das dritte Dokument nicht Teil des Ergebnisses sein darf.

Natürlich können Sie auch eine andere Kartenfunktion schreiben. Die Struktur der Dokumente (ein definiertes Elementdokument und ein Eintragsdokument für jeden Eintrag) kann jedoch nicht geändert werden.


EDIT: Nicht Jason Smith Kommentar zu seiner Antwort verpassen, wo er beschreibt, wie diese kürzer zu tun.

Antwort

50

Vielen Dank! Dies ist ein großartiges Beispiel, um zu zeigen, CouchDB 0.11's new features!

Sie müssen verwenden Sie die Fetch-related-Daten-Funktion Referenzdokumente in der Ansicht. Optional, für komfortablere JSON, verwenden Sie eine _list Funktion zu bereinigen Sie die Ergebnisse. Einzelheiten finden Sie unter Couchio's writeup on "JOIN"s. Hier

ist der Plan:

  1. Erstens haben Sie eine Einzigartigkeit contstraint auf el Dokumente. Wenn zwei von sie id = 2 haben, ist das ein Problem. Es ist notwendig, das Feld _id stattdessen zu verwenden, wenn id. CouchDB garantiert die Eindeutigkeit, aber auch der Rest dieses Plans erfordert _id, um Dokumente per ID zu holen.

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

    Wenn die Dokumente zu ändern absolut unmöglich zu verwenden _id ist, können Sie einen einfachen Blick auf emit(doc.id, doc) erstellen und dann die in eine temporäre Datenbank einfügen wieder. Dies wandelt id in _id um, fügt jedoch etwas Komplexität hinzu.

  2. Die Ansicht sendet {"_id": content_id} Daten, die auf [list_id, sort_number] Keyed sind, um die Listen mit ihrem Inhalt zu "verklumpen".

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

    Jetzt gibt es eine einfache Liste von el Dokumente in der richtigen Reihenfolge. Sie können startkey und endkey verwenden, wenn Sie nur eine bestimmte Liste anzeigen möchten.

    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. Um die el Inhalt, Abfrage mit include_docs=true zu erhalten. Durch die Magie von _id werden die el Dokumente geladen.

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

    Beachten Sie, dies ist bereits alle Informationen, die Sie benötigen. Wenn Ihr Client flexibel ist, können Sie die Informationen aus diesem JSON analysieren. Die nächste optional Schritt einfach formatiert es um zu entsprechen, was Sie brauchen.

  4. Verwenden Sie eine _list-Funktion, die die Ansichtsausgabe einfach neu formatiert. Leute benutzen sie, um XML oder HTML auszugeben, aber wir werden den JSON bequemer machen.

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

    Die Spielergebnisse. Natürlich benötigen Sie in der Produktion startkey und endkey, um die gewünschte Liste anzugeben.

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

Wort, das ist eine gründliche ein. Gute Arbeit jhs! –

+2

Es ist irreführend lang. Eigentlich ist Schritt # 2 eine komplette Lösung, aber ja, ich habe detaillierte Hintergrundanforderungen und optionale Möglichkeiten, um Komfort auf der Client-Seite hinzuzufügen. – JasonSmith

+1

Die CouchIO URL hat sich geändert, hier ist die neue für den gleichen Artikel: http://couchio.tumblr.com/post/446015664/whats-new-in-apache-couchdb-011-part-two – Bdoserror