2010-07-29 22 views
5

Acabo de terminar el libro "couchdb: una guía definitiva" y empecé a jugar con documentos de diseño. Sin embargo, hay una cosa que no entiendo. Todos los ejemplos que he visto hasta ahora son algo lineales.¿Cómo puedo llamar a otra vista en una vista de sofá?

{ 
    "_id": "1", 
    "_rev": ".....", 
    "name": "first", 
    "something": "blue", 
    "child": "2" 
} 

{ 
    "_id": "2", 
    "_rev": ".....", 
    "name": "second", 
    "something": "green", 
    "child": "3" 
    "parent" : "1" 
    } 

{ 
    "_id": "3", 
    "_rev": ".....", 
    "name": "second", 
    "something": "red", 
    "parent" : "2"; 
} 

no tengo ningún problema escribiendo una vista, que devuelve todos los colores:: (!)

function(doc) { 
     if (doc.something) { 
      emit(doc.something,doc._id);  
    } 
} 

Pero lo que si quiero saber todos los descendientes (no

Ejemplo niños, perdón por mi error) por el elemento con _id = 1 ("algo": "azul")? Mi experiencia en programación me dice que debería usar recursividad, pero no sé cómo. ¿Cómo puedo llamar a otra función de vista desde una función de vista?

En general: surge este problema cuando se diseña una base de datos con referencias entre los documentos json. Más específicamente con una relación transitiva entre los elementos.

Editar: Para el ejemplo: sólo sé _id = 1 y el resultado debe ser algo como [_id = 2, _id = 3], ya que 2 es un hijo de 1 y 3 es un hijo de 2.

Respuesta

8

Si es posible, no defina la jerarquía de documentos de esta manera: luchará contra CouchDB en cada paso del camino.

No se puede hacer la caminata de la jerarquía en una vista. Las vistas están pensadas para transferir cada documento de forma independiente en otros (mapa) y generar algún valor agregado de ellos (reducir).

Puede usar listas para operar en varios documentos al mismo tiempo, pero tampoco es una buena solución.

Si es necesario mantener esta estructura de datos (enlaces a padre/hijo), le sugiero que montar la estructura de fuera de CouchDB: obtener el documento de nivel superior, obtener sus hijos, que sus hijos, etc.

Sin embargo, la mejor forma de almacenar un árbol en CouchDB es tener cada nodo recuerda que es camino en el árbol:

{ 
    "_id": "1", 
    "name": "first", 
    "something": "blue", 
    "path": [1] 
} 

{ 
    "_id": "2", 
    "name": "second", 
    "something": "green", 
    "path": [1,2] 
    } 

{ 
    "_id": "3", 
    "name": "second", 
    "something": "red", 
    "path": [1,2,3] 
} 

a continuación, puede utilizar esta vista para obtener los descendientes de un documento:

function(doc) { 
    for (var i in doc.path) { 
     emit([doc.path[i], doc.path], doc) 
    } 
} 

Para obtener descendientes de _id 1 se puede ejecutar esta consulta:

http://c.com/db/_design/colors/_view/descendants?startkey=[1]&endkey=[1,{}] 

Almacenamiento de una ruta completa tiene sus propias desventajas, también, sin embargo. Te sugiero que revises este CouchDB wiki page on trees. La fuente para eso es this blog post by Paul Bonser.

+0

Necesito modelar una relación entre los elementos, como se describe. Sin embargo, tengo el lujo de mover la lógica en una aplicación web java, que de alguna manera es un envoltorio para la aplicación couchdb. Mi intención era mover tanta lógica como sea posible al documento de diseño de couchdb y evitar llamadas múltiples. Probaré los dos enfoques que mencionaste: a) múltiples llamadas a ("obtener el documento principal, obtener sus hijos, obtener sus hijos, etc.") yb) guardar la ruta completa (que es menos deseable) y ver cuál es más rápido/mejor. Gracias por la respuesta. –

+0

Gracias por la pregunta. Aprendí cosas nuevas mientras respondía. Sería increíble si publicara sus hallazgos aquí (o en cualquier lugar de la web) cuando descubra qué es lo mejor para usted. –

1

en el ejemplo que tienes más arriba, para llegar a todos los niños para un ID de documento, su función de mapa sería algo como esto:

function (doc) { 
    if (doc.parent) { 
     emit(doc.parent, { "_id": doc._id }); 
    } 
} 

(la propiedad "niño" que tiene en el documento 2 ni siquiera es necesario.)

Teniendo en cuenta los datos de ejemplo, este emitiría dos veces:

[ "1", { "_id": "2" } ] 
[ "2", { "_id": "3" } ] 

para obtener el ID de niño para un solo progenitor, es posible acceder a la vista de esta manera:

http://.../db/_design/viewName/_view/childfunc?key="2" 

Para obtener el documento completo , agregue el parámetro include_docs a la cadena de consulta.

Si desea obtener el padre y el niño, al mismo tiempo, su función de mapa es un poco diferente:

function (doc) { 
    emit([ doc._id, "" ], { "_id": doc.id }); 
    if (doc.parent) { 
     emit([ doc.parent, doc._id ], { "_id": doc.id }) 
    } 
} 

Esta función puede emitir dos veces, por lo que terminan con lo siguiente:

[ [ "1", "" ], { "_id": "1" } ] 
[ [ "1", "2" ], { "_id": "2" } ] 
[ [ "2", "" ], { "_id": "2" } ] 
[ [ "2", "3" ], { "_id": "3" } ] 
[ [ "3", "" ], { "_id": "3" } ] 

Gracias a la clasificación de clasificación, los padres terminan primero (ya que su segundo elemento clave es "") y los hijos terminan después de eso. No tiene que usar el _id hijo como el segundo elemento clave, puede usar cualquier propiedad de clasificación natural que tenga más sentido. (. Fecha de creación, nombre, título, lo que sea)

Si no tiene la propiedad "niño", se puede hacer una función de reducir para obtener todos los hijos del padre:

function (key, vals) { 
    var children = []; 
    for (var docId in vals) { 
     if (key[1] !== "") { 
      children.push(docId); 
     } 
    } 
    return children; 
} 

Esa función busca si la parte secundaria de la clave no está vacía, y si es así, inserta la ID del documento en una matriz.Pasa por todos los valores de esta manera y devuelve la matriz cuando termina.

+1

He cometido un error. No quise decir niños. Quise decir descendientes. Lo siento. Su solución funciona con el problema del niño. Pero, ¿qué ocurre si necesito acceder a otra función de mapa desde la función de reducción? Por ejemplo, para probar las claves contra otros criterios? ¿No es posible llamar a una función de mapa desde una función de reducción o de mapa? Por ejemplo, si necesito comparar dos o más documentos entre sí? En una función, solo estoy mirando un documento a la vez, pero no puedo comparar dos documentos diferentes sin guardar los valores en algún lugar. –

Cuestiones relacionadas