La mejor forma de hacer uno-a-muchos “UNIRSE” en CouchDB

Estoy buscando un CouchDB equivalente a “SQL joins”.

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

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

Hay un documento que define la lista:

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

Como puede ver, el tercer elemento fue eliminado, 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 está como debería ser. Otro posible resultado:

 { "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 todo lo lejos que puedo llegar. ¿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 puedes 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 se pierda el comentario de Jason Smith sobre su respuesta, donde describe cómo hacerlo más corto.

¡Gracias! ¡Este es un gran ejemplo para mostrar las nuevas características de CouchDB 0.11 !

Debe usar la función de datos relacionados con la recuperación para hacer referencia a documentos en la vista. Opcionalmente, para una JSON más conveniente, use una función _list para limpiar los resultados. Vea el escrito de Couchio en “JOIN” s para más detalles.

Este es el plan:

  1. En primer lugar, tiene una ventaja única en sus documentos. Si dos de ellos tienen id = 2, eso es un problema. En su lugar, es necesario utilizar el campo _id si id . CouchDB garantizará la exclusividad, pero también, el rest 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 cambiar los documentos para usar _id es absolutamente imposible, puede crear una vista simple para emit(doc.id, doc) y luego volver a insertar eso en una base de datos temporal. Esto convierte id en _id pero agrega cierta complejidad.

  2. La vista emite {"_id": content_id} datos codificados en [list_id, sort_number] , para “agrupar” 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 hay una lista simple de los documentos, en el orden correcto. Puede usar las 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 , los documentos se cargarán.

     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. Use una función _list , que simplemente formatea 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á una startkey y una de 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"]}