2010-06-13 5 views
32

Estoy buscando un CouchDB equivalente a "SQL se une".La mejor manera de hacer uno-a-muchos "JOIN" en CouchDB

En mi ejemplo, hay documentos CouchDB que son elementos de la lista:

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

existe un documento que define la lista:

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

Como se puede ver el tercer elemento fue borrado, ya no es parte de la lista. Por lo tanto, no debe ser parte del resultado. Ahora quiero una vista que devuelva los elementos de contenido, incluido el orden correcto.

El resultado podría ser:

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

En este caso, el orden de los elementos ya es como debe ser. Otro resultado posible:

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

empecé a escribir la función de mapa:

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

Esto es lo más lejos que pueda conseguir. ¿Puedes corregir mis errores y escribir una función de reducción? Recuerde que el tercer documento no debe ser parte del resultado.

Por supuesto, también puede escribir una función de mapa diferente. Pero la estructura de los documentos (un documento de elemento definido y un documento de entrada para cada entrada) no se puede cambiar.


EDITAR: No te pierdas el comentario de JasonSmith a su respuesta, donde describe cómo hacerlo más corto.

Respuesta

50

¡Gracias! ¡Este es un gran ejemplo para mostrar CouchDB 0.11's new features!

Debe usar la función de búsqueda de datos relacionados para hacer referencia a los documentos en la vista. Opcionalmente, para una JSON más conveniente, use una función _list para limpie los resultados. Ver Couchio's writeup on "JOIN"s para más detalles.

Aquí es el plan:

  1. En primer lugar, usted tiene una singularidad en sus contstraint el documentos. Si dos de tienen id = 2, eso es un problema. Es necesario usar el campo _id en su lugar si id. CouchDB garantizará la exclusividad, pero también, , el resto de este plan requiere _id para obtener documentos por ID.

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

    Si el cambio de los documentos a utilizar _id es absolutamente imposible, puede crear una vista simple de emit(doc.id, doc) y luego vuelva a insertar las que en una base de datos temporal . Esto convierte id en _id, pero agrega cierta complejidad.

  2. La vista emite {"_id": content_id} datos introducidos en [list_id, sort_number], el "grupo" a las listas con su contenido.

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

    Ahora no es una simple lista de documentos el, en el orden correcto. Puede usar startkey y endkey si desea ver solo una lista en particular.

    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. Para obtener el contenido de el, consulta con include_docs=true. A través de la magia de _id, se cargarán los documentos el.

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

    Aviso, esta es toda la información que necesita. Si su cliente es flexible, puede analizar la información de este JSON. El siguiente paso opcional simplemente lo reformatea para que coincida con lo que necesita.

  4. Utilice la función _list, que simplemente reformatea la salida de la vista. La gente los usa para generar XML o HTML, pero haremos que el JSON sea más 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)); 
    } 
    

    Los resultados coinciden. Por supuesto, en producción necesitará startkey y endkey para especificar la lista que desea.

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

Word, esta es una minuciosa. Buen trabajo jhs! –

+2

Es engañosamente largo. En realidad, el paso # 2 es una solución completa, sin embargo, sí, detallé los requisitos de fondo y las formas opcionales de agregar comodidad en el lado del cliente. – JasonSmith

+1

La URL de CouchIO ha cambiado, aquí está la nueva para el mismo artículo: http://couchio.tumblr.com/post/446015664/whats-new-in-apache-couchdb-011-part-two – Bdoserror

Cuestiones relacionadas