2010-07-28 10 views
5

Diciamo che ho due tipi di documenti memorizzati nel mio database CouchDB. Il primo è con tipo di proprietà impostato su contatto e il secondo su telefono. Il documento del tipo di contatto ha un'altra proprietà denominata nome. Il tipo di telefono ha numero di proprietà e contact_id in modo che possa fare riferimento alla persona di contatto. Questo è uno scenario da molti a molti in cui un contatto può avere numeri di telefono N (so che possono essere incorporati in un singolo documento di contatto, ma ho bisogno di dimostrare uno a molti rapporti con documenti diversi).Visualizzazione CouchDB composizione di oggetti JSON con array incorporati da due documenti separati

esempio Raw dati con Scott avere 2 numeri di telefono e Matt avere 1 numero:

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

funzione Map:

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

ridurre la funzione:

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 è impostato su 1 a causa delle chiavi nella funzione Mappa. Ora posso ottenere i miei contatti con i telefoni inclusi per esempio come questo:

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

Oppure cerca gli qualche contatto con StartKey e endkey come questo:

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

risultati sembrano esattamente come voglio - contatti avranno telefoni incorporati secondo una relazione uno a molti. E qui va la domanda: è questo il modo giusto di usare le funzioni di MapReduce in CouchDB? Ci sono notevoli problemi di prestazioni quando si utilizza questo approccio?

risposta

7

In genere si utilizza meno spazio su disco se non si dispone di emit(...,doc).

Si consiglia di riconsiderare la presenza di una funzione di riduzione. Non è davvero necessario ottenere i dati di cui hai bisogno. Ad esempio, qualcosa sulla falsariga di quanto segue può utilizzare meno spazio su disco ed eseguire meglio se si dispone di un numero enorme di record.

Inoltre, credo che sia contro la tendenza di CouchDB creare più dati in una funzione di riduzione di quella contenuta nei documenti. In questo caso non lo stai facendo, ma stai seguendo uno schema che potrebbe metterti nei guai in seguito. Si chiama riduci per una ragione. :-)

Quindi, qualcosa di simile è più il modo in cui 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 
    }); 
    } 
}

Query per un contatto particolare in questo modo:

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

scontato, non si ottiene risultati nella stessa Struttura JSON come prima, ma credo che questo funzioni meglio in CouchDB.

0

Questa risposta è completamente apocrifa e aneddotica, ma è praticamente esattamente come ho lavorato con le relazioni uno-a-molti in CouchDB. Se ci sono problemi di ridimensionamento, non li ho ancora visti. (Ma ammetto di non aver provato troppo a trovarli.)

Anche se, nella funzione della mappa, il telefono ha ordinato di uscire prima (0) prima del contatto (1)? La tua funzione di riduzione richiede l'ordine opposto.

+0

È ordinato in questo modo perché quando accedo alla vista direttamente tramite browser, dovrei inserire descending = true nell'URL. – yojimbo87

Problemi correlati