2010-07-28 3 views
5

Nehmen wir an, ich habe zwei Arten von Dokumenten in meiner CouchDB-Datenbank gespeichert. Zuerst wird mit dem Eigenschaftstyp Kontakt und zweiten Telefon festgelegt. Kontakttyp Dokument haben eine andere Eigenschaft namens name. Der Telefontyp hat die Eigenschaften number und contact_id, so dass er sich auf die Kontaktperson beziehen kann. Dies ist trivial eins zu viele Szenario, wo ein Kontakt N Rufnummern haben kann (ich weiß, dass sie in ein einziges Kontaktdokument eingebettet werden können, aber ich muss eine Beziehung zwischen mehreren Dokumenten demonstrieren).CouchDB-Ansicht, die JSON-Objekte mit eingebetteten Arrays aus zwei getrennten Dokumenten zusammensetzt

Raw Beispiel Daten mit Scott 2 Telefonnummern und Matt mit 1 Nummer:

{_id: "fc93f785e6bd8c44f14468828b001109", _rev: "1-fdc8d121351b0f5c6d7e288399c7a5b6", type: "phone", number: "123456", contact_id: "fc93f785e6bd8c44f14468828b00099f"} 
{_id: "fc93f785e6bd8c44f14468828b000f6a", _rev: "1-b2dd90295693dc395019deec7cbf89c7", type: "phone", number: "465789", contact_id: "fc93f785e6bd8c44f14468828b00099f"} 
{_id: "fc93f785e6bd8c44f14468828b00099f", _rev: "1-bd643a6b0e90c997a42d8c04c5c06af6", type: "contact", name: "Scott"} 
{_id: "16309fcd03475b9a2924c61d690018e3", _rev: "1-723b7c999111b116c353a4fdab11ddc0", type: "contact", name: "Matt"} 
{_id: "16309fcd03475b9a2924c61d69000aef", _rev: "3-67193f1bfa8ed21c68e3d35847e9060a", type: "phone", number: "789456", contact_id: "16309fcd03475b9a2924c61d690018e3"} 

Map-Funktion:

function(doc) { 
    if (doc.type == "contact") { 
    emit([doc._id, 1], doc); 
    } else if (doc.type == "phone") { 
    emit([doc.contact_id, 0], doc); 
    } 
} 

Reduce Funktion:

function(keys, values) { 
    var output = {}; 

    for(var elem in values) { 
    if(values[elem].type == "contact") { 
     output = { 
     "ID": values[elem]._id, 
     "Name": values[elem].name, 
     "Type": values[elem].type, 
     "Phones": [] 
     }; 
    } else if (values[elem].type == "phone") { 
     output.Phones.push({ 
     "Number": values[elem].number, 
     "Type": values[elem].type 
     }); 
    } 
    } 

    return output; 
} 

group_level wird auf 1 wegen der Tasten in der Kartenfunktion. Jetzt kann ich meine Kontakte mit inbegriffen Telefone zum Beispiel wie diese:

http://localhost:5984/testdb2/_design/testview/_view/tv1?group_level=1 

oder für einen Kontakt mit StartKey und EndKey wie folgt suchen:

http://localhost:5984/testdb2/_design/testview/_view/tv1?group_level=1&startkey=[%22fc93f785e6bd8c44f14468828b00099f%22]&endkey=[%22fc93f785e6bd8c44f14468828b00099f%22,{}] 

Ergebnisse sehen genau, wie ich will - Kontakte haben eingebettete Telefone nach einer Beziehung Und hier geht die Frage: Ist das der richtige Weg, um MapReduce-Funktionen in CouchDB zu verwenden? Gibt es bemerkenswerte Leistungsprobleme bei der Verwendung dieses Ansatzes?

Antwort

7

Im Allgemeinen benötigen Sie weniger Speicherplatz, wenn Sie nicht emit(...,doc).

Vielleicht möchten Sie eine reduktive Funktion noch einmal überdenken. Es ist wirklich nicht nötig, an die Daten zu kommen, die Sie brauchen. Zum Beispiel kann etwas in der folgenden Reihenfolge weniger Speicherplatz belegen und eine bessere Leistung bringen, wenn Sie eine große Anzahl an Datensätzen haben.

Auch ich glaube, es ist gegen den Strich von CouchDB, mehr Daten in einer Reduce-Funktion aufzubauen, als Ihre Dokumente enthalten. Sie tun das in diesem Fall nicht, aber Sie folgen einem Muster, das Sie später in Schwierigkeiten bringen könnte. Es heißt aus einem Grund zu reduzieren. :-)

So etwas wie das ist mehr die Art und Weise CouchDB:

function(doc) { 
    if (doc.type == "contact") { 
    emit([doc._id, 0], { 
     "Name": doc.name, 
     "Type": doc.type 
    }); 
    } else if (doc.type == "phone") { 
    emit([doc.contact_id, 1], { 
     "Number": doc.number, 
     "Type": doc.type 
    }); 
    } 
}

Abfrage es für einen bestimmten Kontakt in etwa so:

http://localhost:5984/testdb2/_design/testview/_view/tv1? 
    startkey=[%22fc93f785e6bd8c44f14468828b00099f%22, 0] 
    &endkey=[%22fc93f785e6bd8c44f14468828b00099f%22,1] 

Zugegeben, Sie keine Anzeigen in der gleichen bekommen JSON-Struktur wie zuvor, aber ich glaube, dass dies in CouchDB besser funktioniert.

0

Diese Antwort ist völlig apokryph und anekdotisch, aber das ist ziemlich genau so, wie ich mit One-to-many Beziehungen in CouchDB gearbeitet habe. Wenn es Skalierungsprobleme gibt, habe ich sie noch nicht gesehen. (Aber ich gebe zu, ich habe nicht versucht, sie zu finden.)

Obwohl, in Ihrer Kartenfunktion warum haben Sie Ihr Telefon sortiert, um zuerst (0) vor dem Kontakt (1) herauskommen? Ihre Reduce-Funktion erfordert die umgekehrte Reihenfolge.

+0

Es ist so sortiert, weil wenn ich die Ansicht direkt über den Browser zugreifen würde ich in der URL absteigend = True einfügen müsste. – yojimbo87

Verwandte Themen